Пример #1
0
// flushGlobalPorts opens and closes global ports in the environment.
// It keeps a reference count for ports so that only 0-to-1 and 1-to-0 events
// modify the environment.
func (fw *Firewaller) flushGlobalPorts(rawOpen, rawClose []network.PortRange) error {
	// Filter which ports are really to open or close.
	var toOpen, toClose []network.PortRange
	for _, portRange := range rawOpen {
		if fw.globalPortRef[portRange] == 0 {
			toOpen = append(toOpen, portRange)
		}
		fw.globalPortRef[portRange]++
	}
	for _, portRange := range rawClose {
		fw.globalPortRef[portRange]--
		if fw.globalPortRef[portRange] == 0 {
			toClose = append(toClose, portRange)
			delete(fw.globalPortRef, portRange)
		}
	}
	// Open and close the ports.
	if len(toOpen) > 0 {
		if err := fw.environ.OpenPorts(toOpen); err != nil {
			// TODO(mue) Add local retry logic.
			return err
		}
		network.SortPortRanges(toOpen)
		logger.Infof("opened port ranges %v in environment", toOpen)
	}
	if len(toClose) > 0 {
		if err := fw.environ.ClosePorts(toClose); err != nil {
			// TODO(mue) Add local retry logic.
			return err
		}
		network.SortPortRanges(toClose)
		logger.Infof("closed port ranges %v in environment", toClose)
	}
	return nil
}
Пример #2
0
// reconcileInstances compares the initially started watcher for machines,
// units and services with the opened and closed ports of the instances and
// opens and closes the appropriate ports for each instance.
func (fw *Firewaller) reconcileInstances() error {
	for _, machined := range fw.machineds {
		m, err := machined.machine()
		if params.IsCodeNotFound(err) {
			if err := fw.forgetMachine(machined); err != nil {
				return err
			}
			continue
		}
		if err != nil {
			return err
		}
		instanceId, err := m.InstanceId()
		if errors.IsNotProvisioned(err) {
			logger.Errorf("Machine not yet provisioned: %v", err)
			continue
		}
		if err != nil {
			return err
		}
		instances, err := fw.environ.Instances([]instance.Id{instanceId})
		if err == environs.ErrNoInstances {
			return nil
		}
		if err != nil {
			return err
		}
		machineId := machined.tag.Id()
		initialPortRanges, err := instances[0].Ports(machineId)
		if err != nil {
			return err
		}

		// Check which ports to open or to close.
		toOpen := diffRanges(machined.openedPorts, initialPortRanges)
		toClose := diffRanges(initialPortRanges, machined.openedPorts)
		if len(toOpen) > 0 {
			logger.Infof("opening instance port ranges %v for %q",
				toOpen, machined.tag)
			if err := instances[0].OpenPorts(machineId, toOpen); err != nil {
				// TODO(mue) Add local retry logic.
				return err
			}
			network.SortPortRanges(toOpen)
		}
		if len(toClose) > 0 {
			logger.Infof("closing instance port ranges %v for %q",
				toClose, machined.tag)
			if err := instances[0].ClosePorts(machineId, toClose); err != nil {
				// TODO(mue) Add local retry logic.
				return err
			}
			network.SortPortRanges(toClose)
		}
	}
	return nil
}
Пример #3
0
// convertEndpointsToPorts converts a slice of gwacl.InputEndpoint into a slice of network.PortRange.
func convertEndpointsToPortRanges(endpoints []gwacl.InputEndpoint) []network.PortRange {
	// group ports by prefix on the endpoint name
	portSets := make(map[string][]network.Port)
	otherPorts := []network.Port{}
	for _, endpoint := range endpoints {
		port := network.Port{
			Protocol: strings.ToLower(endpoint.Protocol),
			Number:   endpoint.Port,
		}
		if strings.Contains(endpoint.Name, "_range_") {
			prefix := strings.Split(endpoint.Name, "_range_")[0]
			portSets[prefix] = append(portSets[prefix], port)
		} else {
			otherPorts = append(otherPorts, port)
		}
	}

	portRanges := []network.PortRange{}

	// convert port sets into port ranges
	for _, ports := range portSets {
		portRanges = append(portRanges, network.CollapsePorts(ports)...)
	}

	portRanges = append(portRanges, network.CollapsePorts(otherPorts)...)
	network.SortPortRanges(portRanges)
	return portRanges
}
Пример #4
0
func makeRanges(stringRanges ...string) []network.PortRange {
	var results []network.PortRange
	for _, s := range stringRanges {
		if strings.Contains(s, "-") {
			parts := strings.Split(s, "-")
			fromPort, _ := strconv.Atoi(parts[0])
			parts = strings.Split(parts[1], "/")
			toPort, _ := strconv.Atoi(parts[0])
			proto := parts[1]
			results = append(results, network.PortRange{
				FromPort: fromPort,
				ToPort:   toPort,
				Protocol: proto,
			})
		} else {
			parts := strings.Split(s, "/")
			port, _ := strconv.Atoi(parts[0])
			proto := parts[1]
			results = append(results, network.PortRange{
				FromPort: port,
				ToPort:   port,
				Protocol: proto,
			})
		}
	}
	network.SortPortRanges(results)
	return results
}
Пример #5
0
// Helper method to get port from the given firewall rules
func getPorts(envName string, rules []cloudapi.FirewallRule) []network.PortRange {
	portRanges := []network.PortRange{}
	for _, r := range rules {
		rule := r.Rule
		if r.Enabled && strings.HasPrefix(rule, "FROM tag "+envName) && strings.Contains(rule, "PORT") {
			if firewallSinglePortRule.MatchString(rule) {
				parts := firewallSinglePortRule.FindStringSubmatch(rule)
				if len(parts) != 3 {
					continue
				}
				protocol := parts[1]
				n, _ := strconv.Atoi(parts[2])
				portRanges = append(portRanges, network.PortRange{Protocol: protocol, FromPort: n, ToPort: n})
			} else if firewallMultiPortRule.MatchString(rule) {
				parts := firewallMultiPortRule.FindStringSubmatch(rule)
				if len(parts) != 3 {
					continue
				}
				protocol := parts[1]
				ports := []network.Port{}
				portStrings := strings.Split(parts[2], " AND ")
				for _, portString := range portStrings {
					portString = portString[strings.LastIndex(portString, "PORT")+5:]
					port, _ := strconv.Atoi(portString)
					ports = append(ports, network.Port{protocol, port})
				}
				portRanges = append(portRanges, network.CollapsePorts(ports)...)
			}
		}
	}

	network.SortPortRanges(portRanges)
	return portRanges
}
Пример #6
0
// AddPorts adds the specified port range.
func (ni *NetworkInterface) AddPorts(protocol string, from, to int) {
	ni.Ports = append(ni.Ports, network.PortRange{
		Protocol: protocol,
		FromPort: from,
		ToPort:   to,
	})
	network.SortPortRanges(ni.Ports)
}
Пример #7
0
// Ports is specified in the Instance interface.
func (azInstance *azureInstance) Ports(machineId string) (ports []network.PortRange, err error) {
	err = azInstance.apiCall(false, func(api *gwacl.ManagementAPI) error {
		ports, err = azInstance.listPorts(api)
		return err
	})
	if ports != nil {
		network.SortPortRanges(ports)
	}
	return ports, err
}
Пример #8
0
// flushInstancePorts opens and closes ports global on the machine.
func (fw *Firewaller) flushInstancePorts(machined *machineData, toOpen, toClose []network.PortRange) error {
	// If there's nothing to do, do nothing.
	// This is important because when a machine is first created,
	// it will have no instance id but also no open ports -
	// InstanceId will fail but we don't care.
	if len(toOpen) == 0 && len(toClose) == 0 {
		return nil
	}
	m, err := machined.machine()
	if params.IsCodeNotFound(err) {
		return nil
	}
	if err != nil {
		return err
	}
	machineId := machined.tag.Id()
	instanceId, err := m.InstanceId()
	if err != nil {
		return err
	}
	instances, err := fw.environ.Instances([]instance.Id{instanceId})
	if err != nil {
		return err
	}
	// Open and close the ports.
	if len(toOpen) > 0 {
		if err := instances[0].OpenPorts(machineId, toOpen); err != nil {
			// TODO(mue) Add local retry logic.
			return err
		}
		network.SortPortRanges(toOpen)
		logger.Infof("opened port ranges %v on %q", toOpen, machined.tag)
	}
	if len(toClose) > 0 {
		if err := instances[0].ClosePorts(machineId, toClose); err != nil {
			// TODO(mue) Add local retry logic.
			return err
		}
		network.SortPortRanges(toClose)
		logger.Infof("closed port ranges %v on %q", toClose, machined.tag)
	}
	return nil
}
Пример #9
0
func (ctx *HookContext) OpenedPorts() []network.PortRange {
	var unitRanges []network.PortRange
	for portRange, relUnit := range ctx.machinePorts {
		if relUnit.Unit == ctx.unit.Tag().String() {
			unitRanges = append(unitRanges, portRange)
		}
	}
	network.SortPortRanges(unitRanges)
	return unitRanges
}
Пример #10
0
// reconcileGlobal compares the initially started watcher for machines,
// units and services with the opened and closed ports globally and
// opens and closes the appropriate ports for the whole environment.
func (fw *Firewaller) reconcileGlobal() error {
	initialPortRanges, err := fw.environ.Ports()
	if err != nil {
		return err
	}
	collector := make(map[network.PortRange]bool)
	for _, machined := range fw.machineds {
		for portRange, unitTag := range machined.definedPorts {
			unitd, known := machined.unitds[unitTag]
			if !known {
				delete(machined.unitds, unitTag)
				continue
			}
			if unitd.serviced.exposed {
				collector[portRange] = true
			}
		}
	}
	wantedPorts := []network.PortRange{}
	for port := range collector {
		wantedPorts = append(wantedPorts, port)
	}
	// Check which ports to open or to close.
	toOpen := diffRanges(wantedPorts, initialPortRanges)
	toClose := diffRanges(initialPortRanges, wantedPorts)
	if len(toOpen) > 0 {
		logger.Infof("opening global ports %v", toOpen)
		if err := fw.environ.OpenPorts(toOpen); err != nil {
			return err
		}
		network.SortPortRanges(toOpen)
	}
	if len(toClose) > 0 {
		logger.Infof("closing global ports %v", toClose)
		if err := fw.environ.ClosePorts(toClose); err != nil {
			return err
		}
		network.SortPortRanges(toClose)
	}
	return nil
}
Пример #11
0
// GetMachinePorts returns the port ranges opened on a machine for the specified
// subnet as a map mapping port ranges to the tags of the units that opened
// them.
func (f *FirewallerAPI) GetMachinePorts(args params.MachinePortsParams) (params.MachinePortsResults, error) {
	result := params.MachinePortsResults{
		Results: make([]params.MachinePortsResult, len(args.Params)),
	}
	canAccess, err := f.accessMachine()
	if err != nil {
		return params.MachinePortsResults{}, err
	}
	for i, param := range args.Params {
		machineTag, err := names.ParseMachineTag(param.MachineTag)
		if err != nil {
			result.Results[i].Error = common.ServerError(err)
			continue
		}
		var subnetTag names.SubnetTag
		if param.SubnetTag != "" {
			subnetTag, err = names.ParseSubnetTag(param.SubnetTag)
			if err != nil {
				result.Results[i].Error = common.ServerError(err)
				continue
			}
		}
		machine, err := f.getMachine(canAccess, machineTag)
		if err != nil {
			result.Results[i].Error = common.ServerError(err)
			continue
		}
		ports, err := machine.OpenedPorts(subnetTag.Id())
		if err != nil {
			result.Results[i].Error = common.ServerError(err)
			continue
		}
		if ports != nil {
			portRangeMap := ports.AllPortRanges()
			var portRanges []network.PortRange
			for portRange := range portRangeMap {
				portRanges = append(portRanges, portRange)
			}
			network.SortPortRanges(portRanges)

			for _, portRange := range portRanges {
				unitTag := names.NewUnitTag(portRangeMap[portRange]).String()
				result.Results[i].Ports = append(result.Results[i].Ports,
					params.MachinePortRange{
						UnitTag:   unitTag,
						PortRange: params.FromNetworkPortRange(portRange),
					})
			}
		}
	}
	return result, nil
}
Пример #12
0
// assertPorts retrieves the open ports of the instance and compares them
// to the expected.
func (s *FirewallerSuite) assertPorts(c *gc.C, inst instance.Instance, machineId string, expected []network.PortRange) {
	s.BackingState.StartSync()
	start := time.Now()
	for {
		got, err := inst.Ports(machineId)
		if err != nil {
			c.Fatal(err)
			return
		}
		network.SortPortRanges(got)
		network.SortPortRanges(expected)
		if reflect.DeepEqual(got, expected) {
			c.Succeed()
			return
		}
		if time.Since(start) > coretesting.LongWait {
			c.Fatalf("timed out: expected %q; got %q", expected, got)
			return
		}
		time.Sleep(coretesting.ShortWait)
	}
}
Пример #13
0
// assertEnvironPorts retrieves the open ports of environment and compares them
// to the expected.
func (s *firewallerBaseSuite) assertEnvironPorts(c *gc.C, expected []network.PortRange) {
	s.BackingState.StartSync()
	start := time.Now()
	for {
		got, err := s.Environ.Ports()
		if err != nil {
			c.Fatal(err)
			return
		}
		network.SortPortRanges(got)
		network.SortPortRanges(expected)
		if reflect.DeepEqual(got, expected) {
			c.Succeed()
			return
		}
		if time.Since(start) > coretesting.LongWait {
			c.Fatalf("timed out: expected %q; got %q", expected, got)
			return
		}
		time.Sleep(coretesting.ShortWait)
	}
}
Пример #14
0
// RemovePorts removes the specified port range.
func (ni *NetworkInterface) RemovePorts(protocol string, from, to int) {
	portRange := network.PortRange{
		Protocol: protocol,
		FromPort: from,
		ToPort:   to,
	}
	for i, port := range ni.Ports {
		if port == portRange {
			ni.Ports = append(ni.Ports[:i], ni.Ports[i+1:]...)
			break
		}
	}
	network.SortPortRanges(ni.Ports)
}
Пример #15
0
func (*PortSuite) TestSortPortRanges(c *gc.C) {
	ranges := []network.PortRange{
		{10, 100, "udp"},
		{80, 90, "tcp"},
		{80, 80, "tcp"},
	}
	expected := []network.PortRange{
		{80, 80, "tcp"},
		{80, 90, "tcp"},
		{10, 100, "udp"},
	}
	network.SortPortRanges(ranges)
	c.Assert(ranges, gc.DeepEquals, expected)
}
Пример #16
0
func (c *defaultFirewaller) portsInGroup(name string) (portRanges []network.PortRange, err error) {
	group, err := c.environ.nova().SecurityGroupByName(name)
	if err != nil {
		return nil, err
	}
	for _, p := range (*group).Rules {
		portRanges = append(portRanges, network.PortRange{
			Protocol: *p.IPProtocol,
			FromPort: *p.FromPort,
			ToPort:   *p.ToPort,
		})
	}
	network.SortPortRanges(portRanges)
	return portRanges, nil
}
Пример #17
0
func (c *defaultFirewaller) portsInGroup(nameRegexp string) (portRanges []network.PortRange, err error) {
	group, err := c.matchingGroup(nameRegexp)
	if err != nil {
		return nil, err
	}
	for _, p := range group.Rules {
		portRanges = append(portRanges, network.PortRange{
			Protocol: *p.IPProtocol,
			FromPort: *p.FromPort,
			ToPort:   *p.ToPort,
		})
	}
	network.SortPortRanges(portRanges)
	return portRanges, nil
}
Пример #18
0
func (e *environ) Ports() (ports []network.PortRange, err error) {
	if mode := e.ecfg().FirewallMode(); mode != config.FwGlobal {
		return nil, fmt.Errorf("invalid firewall mode %q for retrieving ports from environment", mode)
	}
	estate, err := e.state()
	if err != nil {
		return nil, err
	}
	estate.mu.Lock()
	defer estate.mu.Unlock()
	for p := range estate.globalPorts {
		ports = append(ports, p)
	}
	network.SortPortRanges(ports)
	return
}
Пример #19
0
func (inst *dummyInstance) Ports(machineId string) (ports []network.PortRange, err error) {
	defer delay()
	if inst.firewallMode != config.FwInstance {
		return nil, fmt.Errorf("invalid firewall mode %q for retrieving ports from instance",
			inst.firewallMode)
	}
	if inst.machineId != machineId {
		panic(fmt.Errorf("Ports with mismatched machine id, expected %q got %q", inst.machineId, machineId))
	}
	inst.state.mu.Lock()
	defer inst.state.mu.Unlock()
	for p := range inst.ports {
		ports = append(ports, p)
	}
	network.SortPortRanges(ports)
	return
}
Пример #20
0
func (s *instanceSuite) testPorts(c *gc.C, maskStateServerPorts bool) {
	// Update the role's endpoints by hand.
	configSetNetwork(s.role).InputEndpoints = &[]gwacl.InputEndpoint{{
		LocalPort: 223,
		Protocol:  "udp",
		Name:      "test223",
		Port:      2123,
	}, {
		LocalPort: 123,
		Protocol:  "udp",
		Name:      "test123",
		Port:      1123,
	}, {
		LocalPort: 456,
		Protocol:  "tcp",
		Name:      "test456",
		Port:      4456,
	}, {
		LocalPort: s.env.Config().APIPort(),
		Protocol:  "tcp",
		Name:      "apiserver",
		Port:      s.env.Config().APIPort(),
	}}

	responses := preparePortChangeConversation(c, s.role)
	record := gwacl.PatchManagementAPIResponses(responses)
	s.instance.maskStateServerPorts = maskStateServerPorts
	ports, err := s.instance.Ports("machine-id")
	c.Assert(err, jc.ErrorIsNil)
	assertPortChangeConversation(c, *record, []expectedRequest{
		{"GET", ".*/deployments/deployment-one/roles/role-one"}, // GetRole
	})

	expected := []network.PortRange{
		{4456, 4456, "tcp"},
		{1123, 1123, "udp"},
		{2123, 2123, "udp"},
	}
	if !maskStateServerPorts {
		expected = append(expected, network.PortRange{s.env.Config().APIPort(), s.env.Config().APIPort(), "tcp"})
		network.SortPortRanges(expected)
	}
	c.Check(ports, gc.DeepEquals, expected)
}
Пример #21
0
func (s *instanceSuite) TestConvertAndFilterEndpoints(c *gc.C) {
	endpoints := []gwacl.InputEndpoint{
		{
			LocalPort: 123,
			Protocol:  "udp",
			Name:      "test123",
			Port:      1123,
		},
		{
			LocalPort: 456,
			Protocol:  "tcp",
			Name:      "test456",
			Port:      44,
		}}
	endpoints = append(endpoints, s.env.getInitialEndpoints(true)...)
	expectedPorts := []network.PortRange{
		{1123, 1123, "udp"},
		{44, 44, "tcp"}}
	network.SortPortRanges(expectedPorts)
	c.Check(convertAndFilterEndpoints(endpoints, s.env, true), gc.DeepEquals, expectedPorts)
}
Пример #22
0
func (u *UniterAPIV1) getOneMachinePorts(canAccess common.AuthFunc, machineTag string) params.MachinePortsResult {
	tag, err := names.ParseMachineTag(machineTag)
	if err != nil {
		return params.MachinePortsResult{Error: common.ServerError(common.ErrPerm)}
	}
	if !canAccess(tag) {
		return params.MachinePortsResult{Error: common.ServerError(common.ErrPerm)}
	}
	machine, err := u.getMachine(tag)
	if err != nil {
		return params.MachinePortsResult{Error: common.ServerError(err)}
	}
	allPorts, err := machine.AllPorts()
	if err != nil {
		return params.MachinePortsResult{Error: common.ServerError(err)}
	}
	var resultPorts []params.MachinePortRange
	for _, ports := range allPorts {
		// AllPortRanges gives a map, but apis require a stable order
		// for results, so sort the port ranges.
		portRangesToUnits := ports.AllPortRanges()
		portRanges := make([]network.PortRange, 0, len(portRangesToUnits))
		for portRange := range portRangesToUnits {
			portRanges = append(portRanges, portRange)
		}
		network.SortPortRanges(portRanges)
		for _, portRange := range portRanges {
			unitName := portRangesToUnits[portRange]
			resultPorts = append(resultPorts, params.MachinePortRange{
				UnitTag:   names.NewUnitTag(unitName).String(),
				PortRange: params.FromNetworkPortRange(portRange),
			})
		}
	}
	return params.MachinePortsResult{
		Ports: resultPorts,
	}
}
Пример #23
0
func (s *OpenedPortsSuite) TestRunAllFormats(c *gc.C) {
	expectedPorts := []network.PortRange{
		{10, 20, "tcp"},
		{80, 80, "tcp"},
		{53, 55, "udp"},
		{63, 63, "udp"},
	}
	network.SortPortRanges(expectedPorts)
	portsAsStrings := make([]string, len(expectedPorts))
	for i, portRange := range expectedPorts {
		portsAsStrings[i] = portRange.String()
	}
	defaultOutput := strings.Join(portsAsStrings, "\n") + "\n"
	jsonOutput := `["` + strings.Join(portsAsStrings, `","`) + `"]` + "\n"
	yamlOutput := "- " + strings.Join(portsAsStrings, "\n- ") + "\n"

	formatToOutput := map[string]string{
		"":      defaultOutput,
		"smart": defaultOutput,
		"json":  jsonOutput,
		"yaml":  yamlOutput,
	}
	for format, expectedOutput := range formatToOutput {
		hctx := s.getContextAndOpenPorts(c)
		stdout := ""
		stderr := ""
		if format == "" {
			stdout, stderr = s.runCommand(c, hctx)
		} else {
			stdout, stderr = s.runCommand(c, hctx, "--format", format)
		}
		c.Check(stdout, gc.Equals, expectedOutput)
		c.Check(stderr, gc.Equals, "")
		hctx.info.CheckPorts(c, expectedPorts)
	}
}