From 22c4aca5d0d9cacca6e23ff9d11e8a76e8086567 Mon Sep 17 00:00:00 2001 From: Jerzy Kozera Date: Wed, 21 Nov 2018 00:25:47 +0100 Subject: [PATCH] IPv6 support --- daemon/conman/connection.go | 119 ++++++++++++++++++++++++------------ daemon/firewall/rules.go | 2 + daemon/netfilter/queue.go | 4 +- daemon/netstat/parse.go | 41 +++++++++++-- 4 files changed, 120 insertions(+), 46 deletions(-) diff --git a/daemon/conman/connection.go b/daemon/conman/connection.go index 53a28890..45f915e7 100644 --- a/daemon/conman/connection.go +++ b/daemon/conman/connection.go @@ -30,51 +30,65 @@ type Connection struct { func Parse(nfp netfilter.Packet) *Connection { ipLayer := nfp.Packet.Layer(layers.LayerTypeIPv4) - if ipLayer == nil { + ipLayer6 := nfp.Packet.Layer(layers.LayerTypeIPv6) + if ipLayer == nil && ipLayer6 == nil { return nil } - ip, ok := ipLayer.(*layers.IPv4) - if ok == false || ip == nil { - return nil - } + if (ipLayer == nil) { + ip, ok := ipLayer6.(*layers.IPv6) + if ok == false || ip == nil { + return nil + } - // we're not interested in connections - // from/to the localhost interface - if ip.SrcIP.IsLoopback() { - return nil - } + // we're not interested in connections + // from/to the localhost interface + if ip.SrcIP.IsLoopback() { + return nil + } - // skip multicast stuff - if ip.SrcIP.IsMulticast() || ip.DstIP.IsMulticast() { - return nil - } + // skip multicast stuff + if ip.SrcIP.IsMulticast() || ip.DstIP.IsMulticast() { + return nil + } - // skip broadcasted stuff - // FIXME: this is ugly - if ip.DstIP[3] == 0xff { - return nil - } + con, err := NewConnection6(&nfp, ip) + if err != nil { + log.Debug("%s", err) + return nil + } else if con == nil { + return nil + } + return con + } else { + ip, ok := ipLayer.(*layers.IPv4) + if ok == false || ip == nil { + return nil + } - con, err := NewConnection(&nfp, ip) - if err != nil { - log.Debug("%s", err) - return nil - } else if con == nil { - return nil - } + // we're not interested in connections + // from/to the localhost interface + if ip.SrcIP.IsLoopback() { + return nil + } - return con + // skip multicast stuff + if ip.SrcIP.IsMulticast() || ip.DstIP.IsMulticast() { + return nil + } + + con, err := NewConnection(&nfp, ip) + if err != nil { + log.Debug("%s", err) + return nil + } else if con == nil { + return nil + } + return con + } } -func NewConnection(nfp *netfilter.Packet, ip *layers.IPv4) (c *Connection, err error) { - c = &Connection{ - SrcIP: ip.SrcIP, - DstIP: ip.DstIP, - DstHost: dns.HostOr(ip.DstIP, ip.DstIP.String()), - pkt: nfp, - } - +func newConnectionImpl(nfp *netfilter.Packet, c *Connection) (cr *Connection, err error) { // no errors but not enough info neither if c.parseDirection() == false { return nil, nil @@ -94,28 +108,57 @@ func NewConnection(nfp *netfilter.Packet, ip *layers.IPv4) (c *Connection, err e return nil, fmt.Errorf("Could not find process by its pid %d for: %s", pid, c) } return c, nil + +} + +func NewConnection(nfp *netfilter.Packet, ip *layers.IPv4) (c *Connection, err error) { + c = &Connection{ + SrcIP: ip.SrcIP, + DstIP: ip.DstIP, + DstHost: dns.HostOr(ip.DstIP, ip.DstIP.String()), + pkt: nfp, + } + return newConnectionImpl(nfp, c) +} + +func NewConnection6(nfp *netfilter.Packet, ip *layers.IPv6) (c *Connection, err error) { + c = &Connection{ + SrcIP: ip.SrcIP, + DstIP: ip.DstIP, + DstHost: dns.HostOr(ip.DstIP, ip.DstIP.String()), + pkt: nfp, + } + return newConnectionImpl(nfp, c) } func (c *Connection) parseDirection() bool { + ret := false for _, layer := range c.pkt.Packet.Layers() { if layer.LayerType() == layers.LayerTypeTCP { if tcp, ok := layer.(*layers.TCP); ok == true && tcp != nil { c.Protocol = "tcp" c.DstPort = int(tcp.DstPort) c.SrcPort = int(tcp.SrcPort) - return true + ret = true } } else if layer.LayerType() == layers.LayerTypeUDP { if udp, ok := layer.(*layers.UDP); ok == true && udp != nil { c.Protocol = "udp" c.DstPort = int(udp.DstPort) c.SrcPort = int(udp.SrcPort) - return true + ret = true } } } - return false + for _, layer := range c.pkt.Packet.Layers() { + if layer.LayerType() == layers.LayerTypeIPv6 { + if tcp, ok := layer.(*layers.IPv6); ok == true && tcp != nil { + c.Protocol += "6" + } + } + } + return ret } func (c *Connection) To() string { diff --git a/daemon/firewall/rules.go b/daemon/firewall/rules.go index f58961aa..3e1617eb 100644 --- a/daemon/firewall/rules.go +++ b/daemon/firewall/rules.go @@ -27,6 +27,8 @@ func RunRule(enable bool, rule []string) (err error) { // fmt.Printf("iptables %s\n", rule) _, err = core.Exec("iptables", rule) + _, err = core.Exec("ip6tables", rule) + return } diff --git a/daemon/netfilter/queue.go b/daemon/netfilter/queue.go index 77d10940..8f45ce4f 100644 --- a/daemon/netfilter/queue.go +++ b/daemon/netfilter/queue.go @@ -33,8 +33,6 @@ const ( NF_DEFAULT_QUEUE_SIZE uint32 = 4096 NF_DEFAULT_PACKET_SIZE uint32 = 4096 - - ipv4version = 0x40 ) var ( @@ -167,7 +165,7 @@ func go_callback(queueId C.int, data *C.uchar, length C.int, mark C.uint, idx ui xdata := C.GoBytes(unsafe.Pointer(data), length) var packet gopacket.Packet - if xdata[0]&0xf0 == ipv4version { + if (xdata[0] >> 4) == 4 { // first 4 bits is the version packet = gopacket.NewPacket(xdata, layers.LayerTypeIPv4, gopacketDecodeOptions) } else { packet = gopacket.NewPacket(xdata, layers.LayerTypeIPv6, gopacketDecodeOptions) diff --git a/daemon/netstat/parse.go b/daemon/netstat/parse.go index b6e0aee2..2a407cd9 100644 --- a/daemon/netstat/parse.go +++ b/daemon/netstat/parse.go @@ -16,8 +16,8 @@ import ( var ( parser = regexp.MustCompile(`(?i)` + `\d+:\s+` + // sl - `([a-f0-9]{8}):([a-f0-9]{4})\s+` + // local_address - `([a-f0-9]{8}):([a-f0-9]{4})\s+` + // rem_address + `([a-f0-9]{8,32}):([a-f0-9]{4})\s+` + // local_address + `([a-f0-9]{8,32}):([a-f0-9]{4})\s+` + // rem_address `[a-f0-9]{2}\s+` + // st `[a-f0-9]{8}:[a-f0-9]{8}\s+` + // tx_queue rx_queue `[a-f0-9]{2}:[a-f0-9]{8}\s+` + // tr tm->when @@ -44,10 +44,41 @@ func hexToInt(h string) int { return int(d) } + +func hexToInt2(h string) (int, int) { + if len(h) > 16 { + d, err := strconv.ParseInt(h[:16], 16, 64) + if err != nil { + log.Fatal("Error while parsing %s to int: %s", h[16:], err) + } + d2, err := strconv.ParseInt(h[16:], 16, 64) + if err != nil { + log.Fatal("Error while parsing %s to int: %s", h[16:], err) + } + return int(d), int(d2) + } else { + d, err := strconv.ParseInt(h, 16, 64) + if err != nil { + log.Fatal("Error while parsing %s to int: %s", h[16:], err) + } + return int(d), 0 + } +} + func hexToIP(h string) net.IP { - n := hexToInt(h) - ip := make(net.IP, 4) - binary.LittleEndian.PutUint32(ip, uint32(n)) + n, m := hexToInt2(h) + var ip net.IP + if m != 0 { + ip = make(net.IP, 16) + // TODO: Check if this depends on machine endianness? + binary.LittleEndian.PutUint32(ip, uint32(n >> 32)) + binary.LittleEndian.PutUint32(ip[4:], uint32(n)) + binary.LittleEndian.PutUint32(ip[8:], uint32(m >> 32)) + binary.LittleEndian.PutUint32(ip[12:], uint32(m)) + } else { + ip = make(net.IP, 4) + binary.LittleEndian.PutUint32(ip, uint32(n)) + } return ip }