Giter Club home page Giter Club logo

conntrack's People

Contributors

antoninbas avatar carlpett avatar dstiliadis avatar linosgian avatar nullvoidptr avatar ti-mo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

conntrack's Issues

Stats are not yet implemented

The Conntrack (per-CPU) stats constants are already in the package, but requesting stats and parsing the messages are not implemented yet.

Neither err channel nor events channels are closed

Hello,

Not sure if it breaks backwards compatibility or not, but I believe that eventWorker function should close error channel with defer.

The same applies to events channel. It a bit harder to close correctly when all workers are done, but it's correct way to deal with channels. Writer closes channel.

allow get/update of flows based only on the tupleReply

Hi @ti-mo

In the current implementation updates/gets with a flow that has only the tupleReply defined are blocked by marshal and return an error. This is not required by the netlink API though. Even though for create both are needed, one can update a flow if only the tupleReply information is needed. This is useful when one only cares about the tupleReply state and not the original state.

I have a PR where this seems to work, but I was wondering if there is some other reason for
that choice that I am missing.

Do you see any issues with that? If not, I can create PR.

Any interest in switching from net.IP to netip.Addr to encode IP addresses in Flows?

The netip package was introduced in Go 1.18. Compared to the existing net.IP type, the netip.Addr type takes less memory, is immutable, and is comparable so it supports == and can be used as a map key.

// Sizes: (64-bit)
//   net.IP:     24 byte slice header + {4, 16} = 28 to 40 bytes
//   net.IPAddr: 40 byte slice header + {4, 16} = 44 to 56 bytes + zone length
//   netip.Addr: 24 bytes (zone is per-name singleton, shared across all users)

The Flow type for this library contains 3 fields of type Tuple, each with 2 IP addresses, that's 6 IP addresses in total. For IPv6 connections, memory usage (when considering IP addresses only, not other fields), could go down from 40*6 = 240B to 24*6 = 144B. And in practice, for IPv4 addresses, we would see the same benefit, due to a bug in the unmarshalling code:

conntrack/tuple.go

Lines 117 to 128 in 7b6dc48

switch ipTupleType(ad.Type()) {
case ctaIPv4Src:
ipt.SourceAddress = net.IPv4(b[0], b[1], b[2], b[3])
case ctaIPv6Src:
ipt.SourceAddress = net.IP(b)
case ctaIPv4Dst:
ipt.DestinationAddress = net.IPv4(b[0], b[1], b[2], b[3])
case ctaIPv6Dst:
ipt.DestinationAddress = net.IP(b)
default:
return fmt.Errorf("child type %d: %w", ad.Type(), errUnknownAttribute)
}

Calling net.IPv4(...) creates a 16B slice (+ 24B slice header): https://cs.opensource.google/go/go/+/refs/tags/go1.21.1:src/net/ip.go;l=50-53

One thing to keep in mind is that it would be a non-backward compatible change, but:

This is something I am happy to contribute. It will enable programs consuming this library to reduce their memory footprint, as well as start using the netip package more easily.

ProtoInfoTCP unmarshal: need (at least) 2 child attributes

Hello 👋🏻

When I use this library on kernel 5.10.178-162.673.amzn2.x86_64 I don't get any issues but when I deploy on 5.15.0-1031-aws library works but sometimes throws the below error and stops capturing the events.

ProtoInfoTCP unmarshal: need (at least) 2 child attributes

I logged packages with this library and conntrack at the same time and I noticed close is shown as an update on conntrack and may be this breaks lib.

 [UPDATE] tcp      6 60 SYN_RECV src=XXXX dst=172.17.0.2 sport=54558 dport=8080 src=172.17.0.2 dst=XXXX sport=8080 dport=54558
 [UPDATE] tcp      6 10 CLOSE src=XXXX dst=172.17.0.2 sport=54556 dport=8080 src=172.17.0.2 dst=XXXX sport=8080 dport=54556 [ASSURED]

other close events

[DESTROY] tcp      6 CLOSE src=XXXX dst=172.17.0.2 sport=53256 dport=8080 src=172.17.0.2 dst=XXXX sport=8080 dport=53256 [ASSURED]

Listen integration test suite

Conn.Listen() is not yet taken into account in the integration test suite. Write a test suite that subscribes to Create, Update, Destroy, and simulate those events taking place.

Marshal Label attribute to update label of conntrack

Marshaling Label and LabelMask attributes are needed when Conn.Update try to change the Label of Conntrack
Here are my changes:

diff --git a/flow.go b/flow.go
index 07617f1..a1b3c35 100644
--- a/flow.go
+++ b/flow.go
@@ -267,6 +267,18 @@ func (f Flow) marshal() ([]netfilter.Attribute, error) {
                attrs = append(attrs, f.SynProxy.marshal())
        }

+       if len(f.Labels) > 0 {
+               a := netfilter.Attribute{Type: uint16(ctaLabels)}
+               a.Data = f.Labels
+               attrs = append(attrs, a)
+       }
+
+       if len(f.LabelsMask) > 0 {
+               a := netfilter.Attribute{Type: uint16(ctaLabelsMask)}
+               a.Data = f.LabelsMask
+               attrs = append(attrs, a)
+       }
+

Feature: change buffer size of netfilter socket

Hi,
I recently used this module on a high-bandwidth server and got regular crashes because the netlink socket buffer was filled up. To counter this issue I would like to increase the buffer size of the underlying netlink socket, but conntrack does not provide the necessary methods yet.

I'm willing to implement this feature and send a PR if I get some guidance from the author.

The used netlink package already has a method to change the buffer size: netlink.Conn.SetReadBuffer, so I see two possible solutions:

  1. conntrack.Conn could itself has a method SetReadBuffer which in turn calls a new SetReadBuffer method on netfilter.Conn, which in turn calls this method on netlink.Conn.
  2. conntrack.Conn somehow exposes the underlying netlink.Conn connection so that users can change this (and possibly other) parameters on the netlink connection.

What would be the easiest and cleanest possibility to change a netlink socket's buffer size?

Error "ProtoInfoTCP unmarshal: need (at least) 2 child attributes" on Ubuntu 22.04

When I upgraded my system from Ubuntu 20.04 to 22.04 I got the error "ProtoInfoTCP unmarshal: need (at least) 2 child attributes".
The received netlink msg is below

{{212 unknown(258) 0 0 0} [2 0 0 0 52 0 1 128 20 0 1 128 8 0 1 0 10 0 100 52 8 0 2 0 10 208 240 84 28 0 2 128 5 0 1 0 6 0 0 0 6 0 2 0 237 238 0 0 6 0 3 0 1 187 0 0 52 0 2 128 20 0 1 128 8 0 1 0 10 208 240 84 8 0 2 0 10 208 229 115 28 0 2 128 5 0 1 0 6 0 0 0 6 0 2 0 1 187 0 0 6 0 3 0 237 238 0 0 8 0 12 0 247 95 136 190 8 0 3 0 0 0 3 158 28 0 9 128 12 0 1 0 0 0 0 0 0 0 0 16 12 0 2 0 0 0 0 0 0 0 5 119 28 0 10 128 12 0 1 0 0 0 0 0 0 0 0 14 12 0 2 0 0 0 0 0 0 0 18 39 16 0 4 128 12 0 1 128 5 0 1 0 8 0 0 0]}
netlink msg header: <Subsystem: NFSubsysCTNetlink, Message Type: 2, Family: ProtoIPv4, Version: 0, ResourceID: 0>

Seems this check (https://github.com/ti-mo/conntrack/blob/master/attribute_types.go#L153) failed because the received data has TCP_STATE only.
Is it good to remove the check?

Allow walking the message without a full unmarshal?

I'm using conntrack (thanks!) for doing some fairly simple monitoring of dropped connections and was looking for ways to reduce garbage / CPU spent in GC for flows where only a few attributes were being called. I wanted to specifically defer full unmarshal in the event that a few basic criteria weren't met (protocol, port, flow status, etc). Would you consider an API addition to conntrack/netfilter that allows walking the message without fully decoding?

As an example of the structure I was using in a fork:

		ok, err := netfilter.WalkMessage(
			recv[0],
			func(h netfilter.Header) (bool, error) {
				if h.SubsystemID != netfilter.NFSubsysCTNetlink {
					return false, nil
				}
				if err := event.Type.Unmarshal(h); err != nil {
					return false, err
				}
				switch event.Type {
				case conntrack.EventDestroy, conntrack.EventUpdate:
					return true, nil
				default:
					return false, nil
				}
			},
			func(attr netfilter.Attribute) (bool, error) {
				switch conntrack.AttributeType(attr.Type) {
				case conntrack.CTAStatus:
					if event.Type != conntrack.EventDestroy {
						return true, nil
					}
					if err := flow.Unmarshal([]netfilter.Attribute{attr}); err != nil {
						return false, err
					}
					if flow.Status.SeenReply() {
						return false, nil
					}
				case conntrack.CTATupleOrig:
					if err := attr.UnmarshalNested(); err != nil {
						return false, err
					}
					if err := flow.Unmarshal([]netfilter.Attribute{attr}); err != nil {
						return false, err
					}
					if flow.TupleOrig.Proto.Protocol != unix.IPPROTO_TCP {
						return false, nil
					}
				}
				return true, nil
			},
		)

and the implementations might look like:

// WalkMessage unmarshals a netlink.Message into a Netfilter Header and Attributes.
func WalkMessage(msg netlink.Message, hdrFn func(Header) (bool, error), attrFn func(Attribute) (bool, error)) (bool, error) {
	var h Header
	err := h.unmarshal(msg)
	if err != nil {
		return false, err
	}
	ok, err := hdrFn(h)
	if err != nil {
		return false, err
	}
	if !ok {
		return false, nil
	}
	return WalkAttributes(msg.Data[nfHeaderLen:], attrFn)
}

// WalkAttributes steps through a net link message, invoking fn
// once per Attribute structure.
func WalkAttributes(b []byte, fn func(Attribute) (bool, error)) (bool, error) {
	// Obtain a list of parsed netlink attributes possibly holding
	// nested Netfilter attributes in their binary Data field.
	attrs, err := netlink.UnmarshalAttributes(b)
	if err != nil {
		return false, errors.Wrap(err, errWrapNetlinkUnmarshalAttrs)
	}

	for _, nla := range attrs {
		// Copy the netlink attribute's fields into the netfilter attribute.
		nfa := Attribute{
			// Only consider the rightmost 14 bits for Type
			Type: nla.Type & ^(uint16(unix.NLA_F_NESTED) | uint16(unix.NLA_F_NET_BYTEORDER)),
			Data: nla.Data,
		}

		// Boolean flags extracted from the two leftmost bits of Type
		nfa.Nested = (nla.Type & uint16(unix.NLA_F_NESTED)) != 0
		nfa.NetByteOrder = (nla.Type & uint16(unix.NLA_F_NET_BYTEORDER)) != 0

		if nfa.NetByteOrder && nfa.Nested {
			return false, errInvalidAttributeFlags
		}

		ok, err := fn(nfa)
		if err != nil {
			return false, err
		}
		if !ok {
			return false, nil
		}
	}

	return true, nil
}

This does require public access to some of the constants and unmarshal methods to make practical - is that something you'd be willing to accept a PR for? I had planned on raising a similar ask to mdlayher/netlink to allow the attributes to be walked instead of allocated, but even without that I was able to cut allocations by 90% for the core loop.

Counter unmarshaling fails if nf_conntrack_helper is enabled

Compiling on MIPS for my OpenWRT router discovered that conntrack flows were not being decoded properly. Attempting to print counters for flows returned by Dump() resulted in the following error:

need exactly 2 child attributes for attribute type ctaCountersOrig/ctaCountersReply

The issue is that my router has nf_conntrack_helper set to 'N' rather than default 0. (Why OpenWRT is setting this value rather than '1' I'm not sure):

root@router:~# cat /sys/module/nf_conntrack/parameters/nf_conntrack_helper 
N

When enabled, this embeds 2 additional attributes into the Children slice, causing the check of number of children in (*Counter) unmarshal() to fail. A small change to the function to allow more children and to ignore any of type ctaHelp allows unmarshaling to complete without error.

Conntrack event listener missing some update events (tcp state changes) for iperf traffic.

I expect I can see the tcp state changes (SYN_SENT/SYN_RECV/ESTABLISHEDFIN_WAIT….etc) when I have a tcp connection. However, when I use iperf3 (iperf3 -c 10.244.2.9 -t 1) to have a tcp connection, I have following results:

In conntrack -E (or event listener), there is only one tcp state (SYN_SENT).
TIME_WAIT/CLOSE/CLOSE_WAIT is supposed to appear in events when a connection ends, but I can’t see any of them when using iperf.

[1685571135.590407]  [NEW] tcp   6 120 SYN_SENT src=10.244.1.6 dst=10.244.2.9 sport=49400 dport=5201 [UNREPLIED] src=10.244.2.9 dst=10.244.1.6 sport=5201 dport=49400 zone=65520
[1685571135.590491] [UPDATE] tcp   6 120 src=10.244.1.6 dst=10.244.2.9 sport=49400 dport=5201 [UNREPLIED] src=10.244.2.9 dst=10.244.1.6 sport=5201 dport=49400 mark=3 zone=65520
[1685571135.592658]  [NEW] tcp   6 120 SYN_SENT src=10.244.1.6 dst=10.244.2.9 sport=49402 dport=5201 [UNREPLIED] src=10.244.2.9 dst=10.244.1.6 sport=5201 dport=49402 zone=65520
[1685571135.592697] [UPDATE] tcp   6 120 src=10.244.1.6 dst=10.244.2.9 sport=49402 dport=5201 [UNREPLIED] src=10.244.2.9 dst=10.244.1.6 sport=5201 dport=49402 mark=3 zone=65520

In conntrack -L (or DumpFilter), I can see the tcp state is changed to TIME_WAIT, which is supposed to be in conntrack events, but it isn’t.

tcp   6 104 TIME_WAIT src=10.244.1.6 dst=10.244.2.9 sport=52730 dport=5201 packets=18 bytes=1375 src=10.244.2.9 dst=10.244.1.6 sport=5201 dport=52730 packets=18 bytes=1247 [ASSURED] mark=3 zone=65520 delta-time=17 use=1
tcp   6 104 TIME_WAIT src=10.244.1.6 dst=10.244.2.9 sport=52732 dport=5201 packets=39669 bytes=1448346109 src=10.244.2.9 dst=10.244.1.6 sport=5201 dport=52732 packets=24397 bytes=1269164 [ASSURED] mark=3 zone=65520 delta-time=17 use=1

But if I use wget, I can see all the tcp states in events:

[1685572749.172775]	    [NEW] tcp      6 120 SYN_SENT src=10.244.1.6 dst=142.250.191.68 sport=44606 dport=80 [UNREPLIED] src=142.250.191.68 dst=172.18.0.3 sport=80 dport=44606
[1685572749.212094]	 [UPDATE] tcp      6 60 SYN_RECV src=10.244.1.6 dst=142.250.191.68 sport=44606 dport=80 src=142.250.191.68 dst=172.18.0.3 sport=80 dport=44606
[1685572749.212144]	 [UPDATE] tcp      6 432000 ESTABLISHED src=10.244.1.6 dst=142.250.191.68 sport=44606 dport=80 src=142.250.191.68 dst=172.18.0.3 sport=80 dport=44606 [ASSURED]
[1685572749.350889]	 [UPDATE] tcp      6 120 FIN_WAIT src=10.244.1.6 dst=142.250.191.68 sport=44606 dport=80 src=142.250.191.68 dst=172.18.0.3 sport=80 dport=44606 [ASSURED]
[1685572749.351111]	 [UPDATE] tcp      6 3600 CLOSE_WAIT src=10.244.1.6 dst=142.250.191.68 sport=44606 dport=80 src=142.250.191.68 dst=172.18.0.3 sport=80 dport=44606 [ASSURED]
[1685572749.385305]	 [UPDATE] tcp      6 30 LAST_ACK src=10.244.1.6 dst=142.250.191.68 sport=44606 dport=80 src=142.250.191.68 dst=172.18.0.3 sport=80 dport=44606 [ASSURED]
[1685572749.385362]	 [UPDATE] tcp      6 120 TIME_WAIT src=10.244.1.6 dst=142.250.191.68 sport=44606 dport=80 src=142.250.191.68 dst=172.18.0.3 sport=80 dport=44606 [ASSURED]

I got same results when using Conn.Listen()

I'm wondering the reason why I can’t see the TIME_WAIT event when using iperf?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.