Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Cannot parse negated CIDR ex: "!192.168.122.0/24" #70

Open
stealthybox opened this issue Sep 12, 2019 · 1 comment
Open

Cannot parse negated CIDR ex: "!192.168.122.0/24" #70

stealthybox opened this issue Sep 12, 2019 · 1 comment

Comments

@stealthybox
Copy link

stealthybox commented Sep 12, 2019

Calling ipt.StructuredStats("nat", "POSTROUTING") when rules have negated ranges can error:

invalid CIDR address: !192.168.122.0/24%!(EXTRA string=could not parse destination)

On my machine, I set up a virtual bridge for this subnet, and these iptables rules were auto-created:

ifconfig virbr0; \
sudo iptables -L | grep 192.168; \
sudo iptables -t nat -L POSTROUTING | grep 192.168 \

virbr0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 192.168.122.1  netmask 255.255.255.0  broadcast 192.168.122.255
        ether 06:79:79:15:1a:de  txqueuelen 1000  (Ethernet)
        RX packets 76642  bytes 4332785 (4.3 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 476675  bytes 726146534 (726.1 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ACCEPT     all  --  anywhere             192.168.122.0/24     ctstate RELATED,ESTABLISHED
ACCEPT     all  --  192.168.122.0/24     anywhere            
RETURN     all  --  192.168.122.0/24     base-address.mcast.net/24 
RETURN     all  --  192.168.122.0/24     255.255.255.255     
MASQUERADE  tcp  --  192.168.122.0/24    !192.168.122.0/24     masq ports: 1024-65535
MASQUERADE  udp  --  192.168.122.0/24    !192.168.122.0/24     masq ports: 1024-65535
MASQUERADE  all  --  192.168.122.0/24    !192.168.122.0/24   

ignite uses this library call to cleanup chains, and these MASQ rules fail to net.ParseCIDR due to the leading exclamation mark negating the subnet: weaveworks/ignite#393


Here's a minimal reproduction:

Test Code
package main

import (
	"fmt"

	"github.com/coreos/go-iptables/iptables"
)

// testActual is a forked version of ipt.StructuredStats() that prints debug info
func testActual(ipt *iptables.IPTables) ([]iptables.Stat, error) {
	table := "nat"
	chain := "POSTROUTING"

	rawStats, err := ipt.Stats(table, chain)
	if err != nil {
		return nil, err
	}

	structStats := []iptables.Stat{}
	for _, rawStat := range rawStats {
		fmt.Println(rawStat[7], rawStat[8])
		stat, err := ipt.ParseStat(rawStat)
		if err != nil {
			fmt.Println("rawStat: ", rawStat)
			fmt.Println("stat:    ", stat)
			fmt.Println("err:     ", err)
			return nil, err
		}
		structStats = append(structStats, stat)
	}

	return structStats, nil
}

func minimalReproduction(ipt *iptables.IPTables) (iptables.Stat, error) {
	return ipt.ParseStat(
		[]string{
			"1859",
			"112600",
			"MASQUERADE",
			"tcp",
			"--",
			"*",
			"*",
			"192.168.122.0/24",
			"!192.168.122.0/24",
			"masq ports: 1024-65535",
		},
	)
}

func main() {
	ipt, _ := iptables.NewWithProtocol(iptables.ProtocolIPv4)
	fmt.Println("minimalReproduction")
	fmt.Println(minimalReproduction(ipt))
	fmt.Println()
	fmt.Println("testActual")
	fmt.Println(testActual(ipt))
}

Test logs:

sudo $(which go) run ./testnet.go
minimalReproduction
{1859 112600      192.168.122.0/24 <nil> } invalid CIDR address: !192.168.122.0/24%!(EXTRA string=could not parse destination)

testActual
172.19.0.0/16 0.0.0.0/0
172.17.0.0/16 0.0.0.0/0
192.168.122.0/24 224.0.0.0/24
192.168.122.0/24 255.255.255.255/32
192.168.122.0/24 !192.168.122.0/24
rawStat:  [1883 114040 MASQUERADE tcp -- * * 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535]
stat:     {1883 114040      192.168.122.0/24 <nil> }
err:      invalid CIDR address: !192.168.122.0/24%!(EXTRA string=could not parse destination)
[] invalid CIDR address: !192.168.122.0/24%!(EXTRA string=could not parse destination)
stealthybox added a commit to stealthybox/ignite that referenced this issue Sep 13, 2019
move fmt.Sprintf out of loop
access stat.Options through rawStat[9] with hard-coded index
only parse for IPNet when we are working with the proper ignite CNI rules
  ^ avoids coreos/go-iptables#70
stealthybox added a commit to stealthybox/ignite that referenced this issue Sep 13, 2019
move fmt.Sprintf out of loop
access stat.Options through rawStat[9] with hard-coded index
remove break in the event there are multiple rules per containerID
only parse for IPNet when we are working with the proper ignite CNI rules
  ^ avoids coreos/go-iptables#70
stealthybox added a commit to stealthybox/ignite that referenced this issue Sep 13, 2019
move fmt.Sprintf out of loop
access stat.Options through rawStat[9] with hard-coded index
remove break in the event there are multiple rules per containerID
only parse for IPNet when we are working with the proper ignite CNI rules
  ^ avoids coreos/go-iptables#70
@nor1su
Copy link

nor1su commented May 21, 2024

type CustomStat struct {
    Packets     uint64 `json:"pkts"`
    Bytes       uint64 `json:"bytes"`
    Target      string `json:"target"`
    Protocol    string `json:"prot"`
    Opt         string `json:"opt"`
    Input       string `json:"in"`
    Output      string `json:"out"`
    Source      string `json:"source"`
    Destination string `json:"destination"`
    Port        string `json:"port"`
    Options     string `json:"options"`
}

func parseIptablesOutput(output string) ([]CustomStat, error) {
    var customStats []CustomStat
    scanner := bufio.NewScanner(strings.NewReader(output))
    for scanner.Scan() {
        line := scanner.Text()
        fields := strings.Fields(line)
        if len(fields) < 10 {
            continue
        }
        packets, _ := strconv.ParseUint(fields[0], 10, 64)
        bytes, _ := strconv.ParseUint(fields[1], 10, 64)
        customStats = append(customStats, CustomStat{
            Packets:     packets,
            Bytes:       bytes,
            Target:      fields[2],
            Protocol:    fields[3],
            Opt:         fields[4],
            Input:       fields[5],
            Output:      fields[6],
            Source:      fields[7],
            Destination: fields[8],
            Options:     strings.Join(fields[9:], " "),
        })
    }
    return customStats, scanner.Err()
} 

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants