func (svc *service) startRejecting(s *model.Service) (serviceState, error) { log.Info("rejecting service: ", s.Summary()) rule := []interface{}{ "-p", "tcp", "-d", s.IP, "--dport", s.Port, "-j", "REJECT", } err := svc.ipTables.addRule("filter", rule) if err != nil { return nil, err } return rejecting(func() { svc.ipTables.deleteRule("filter", rule) }), nil }
func (fc forwardingConfig) start(svc *model.Service) (serviceState, error) { log.Info("forwarding service: ", svc.Summary()) ip, err := bridgeIP(fc.bridge) if err != nil { return nil, err } listener, err := net.ListenTCP("tcp", &net.TCPAddr{IP: ip}) if err != nil { return nil, err } success := false defer func() { if !success { listener.Close() } }() rule := []interface{}{ "-p", "tcp", "-d", svc.IP, "--dport", svc.Port, "-j", "DNAT", "--to-destination", listener.Addr(), } err = fc.ipTables.addRule("nat", rule) if err != nil { return nil, err } fwd := &forwarding{ forwardingConfig: fc, rule: rule, listener: listener, Service: svc, } fwd.chooseShim() go fwd.run() success = true return fwd, nil }
func (fwd *forwarding) update(svc *model.Service) (bool, error) { if len(svc.Instances) == 0 { return false, nil } fwd.lock.Lock() defer fwd.lock.Unlock() if svc.Equal(fwd.Service) { return true, nil } if !svc.IP.Equal(fwd.Service.IP) || svc.Port != fwd.Service.Port { return false, nil } log.Info("forwarding service: ", svc.Summary()) fwd.Service = svc fwd.chooseShim() return true, nil }
func TestServices(t *testing.T) { nc := netConfig{ chain: "FLUX", bridge: "lo", } mipt := newMockIPTables(t) ipTables := newIPTables(nc, mipt.cmd) ipTables.start() errorSink := daemon.NewErrorSink() updates := make(chan model.ServiceUpdate) done := make(chan struct{}, 1) svcs := servicesConfig{ netConfig: nc, updates: updates, ipTables: ipTables, eventHandler: events.NullHandler{}, errorSink: errorSink, done: done, }.start() ip := net.ParseIP("127.42.0.1") port := 8888 // Add a service svc := model.Service{ Name: "service", Protocol: "tcp", IP: ip, Port: port, Instances: []model.Instance{ { Name: "foo", Group: "bar", IP: net.ParseIP("127.0.0.1"), Port: 10000, }, }, } updates <- model.ServiceUpdate{Service: svc} <-done requireForwarding(t, &mipt) insts := []model.Instance{ { Name: "foo", Group: "bar", IP: net.ParseIP("127.0.0.1"), Port: 10001, }, } // Update it svc.Instances = insts updates <- model.ServiceUpdate{Service: svc} <-done requireForwarding(t, &mipt) // forwarding -> rejecting svc.Instances = nil updates <- model.ServiceUpdate{Service: svc} <-done requireRejecting(t, &mipt) // rejecting -> not forwarding svc.IP = nil svc.Port = 0 updates <- model.ServiceUpdate{Service: svc} <-done requireNotForwarding(t, &mipt) // not forwarding -> forwarding svc.IP = ip svc.Port = port svc.Instances = insts updates <- model.ServiceUpdate{Service: svc} <-done requireForwarding(t, &mipt) // Now back the other way // forwarding -> not forwarding svc.IP = nil svc.Port = 0 updates <- model.ServiceUpdate{Service: svc} <-done requireNotForwarding(t, &mipt) // not forwarding -> rejecting svc.IP = ip svc.Port = port svc.Instances = nil updates <- model.ServiceUpdate{Service: svc} <-done requireRejecting(t, &mipt) // Delete it updates <- model.ServiceUpdate{Service: svc, Delete: true} <-done requireNotForwarding(t, &mipt) // Delete it, even though it doesn't exist updates <- model.ServiceUpdate{Service: svc, Delete: true} <-done svcs.close() }