mirror of
https://github.com/slackhq/nebula.git
synced 2026-11-15 12:36:52 +01:00
Only read IPv4 ports from TCP and UDP
This commit is contained in:
1 parent
7cfa47d569
commit
11a4298c36
3 files changed
+50
-9
No files matched your search
@@ -459,6 +459,7 @@ firewall:
|
||||
# - port: Takes `0` or `any` as any, a single number `80`, a range `200-901`, or `fragment` to match second and further fragments of fragmented packets (since there is no port available).
|
||||
# proto: `any`, `tcp`, `udp`, or `icmp`
|
||||
# a port specification is ignored if proto is `icmp`
|
||||
# only tcp and udp packets have ports, packets of any other protocol only match port `any` or `fragment`
|
||||
# host: `any` or a literal hostname, ie `test-host`
|
||||
# group: `any` or a literal group name, ie `default-group`
|
||||
# groups: Same as group but accepts a list of values. Multiple values are AND'd together and a certificate would have to contain all groups to pass
|
||||
|
||||
+19
-7
@@ -456,15 +456,27 @@ func parseV4(data []byte, incoming bool, fp *firewall.ParsedPacket) error {
|
||||
if fp.Fragment {
|
||||
fp.RemotePort = 0
|
||||
fp.LocalPort = 0
|
||||
} else if fp.Protocol == iputil.IPProtocolICMP { //note that orientation doesn't matter on ICMP
|
||||
return nil
|
||||
}
|
||||
|
||||
switch fp.Protocol {
|
||||
case iputil.IPProtocolICMP: //note that orientation doesn't matter on ICMP
|
||||
fp.RemotePort = binary.BigEndian.Uint16(data[ihl+4 : ihl+6]) //identifier
|
||||
fp.LocalPort = 0 //code would be uint16(data[ihl+1])
|
||||
} else if incoming {
|
||||
fp.RemotePort = binary.BigEndian.Uint16(data[ihl : ihl+2]) //src port
|
||||
fp.LocalPort = binary.BigEndian.Uint16(data[ihl+2 : ihl+4]) //dst port
|
||||
} else {
|
||||
fp.LocalPort = binary.BigEndian.Uint16(data[ihl : ihl+2]) //src port
|
||||
fp.RemotePort = binary.BigEndian.Uint16(data[ihl+2 : ihl+4]) //dst port
|
||||
|
||||
case iputil.IPProtocolTCP, iputil.IPProtocolUDP:
|
||||
if incoming {
|
||||
fp.RemotePort = binary.BigEndian.Uint16(data[ihl : ihl+2]) //src port
|
||||
fp.LocalPort = binary.BigEndian.Uint16(data[ihl+2 : ihl+4]) //dst port
|
||||
} else {
|
||||
fp.LocalPort = binary.BigEndian.Uint16(data[ihl : ihl+2]) //src port
|
||||
fp.RemotePort = binary.BigEndian.Uint16(data[ihl+2 : ihl+4]) //dst port
|
||||
}
|
||||
|
||||
default:
|
||||
// don't set ports for protocols Nebula doesn't inspect, the first 4 bytes of GRE, IPIP, AH, etc. are not ports
|
||||
fp.RemotePort = 0
|
||||
fp.LocalPort = 0
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
+30
-2
@@ -77,7 +77,7 @@ func Test_newPacket(t *testing.T) {
|
||||
// account for variable ip header length - outgoing
|
||||
h = ipv4.Header{
|
||||
Version: 1,
|
||||
Protocol: 2,
|
||||
Protocol: iputil.IPProtocolUDP,
|
||||
Len: 100,
|
||||
Src: net.IPv4(10, 0, 0, 1),
|
||||
Dst: net.IPv4(10, 0, 0, 2),
|
||||
@@ -89,7 +89,7 @@ func Test_newPacket(t *testing.T) {
|
||||
err = newPacket(b, false, p)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, uint8(2), p.Protocol)
|
||||
assert.Equal(t, uint8(iputil.IPProtocolUDP), p.Protocol)
|
||||
assert.Equal(t, netip.MustParseAddr("10.0.0.1"), p.LocalAddr)
|
||||
assert.Equal(t, netip.MustParseAddr("10.0.0.2"), p.RemoteAddr)
|
||||
assert.Equal(t, uint16(6), p.RemotePort)
|
||||
@@ -97,6 +97,34 @@ func Test_newPacket(t *testing.T) {
|
||||
assert.False(t, p.Fragment)
|
||||
}
|
||||
|
||||
// Test_newPacket_v4NoPorts ensures only TCP and UDP report ports. The first 4 bytes of other protocols are not ports,
|
||||
// and are often chosen by the sender: a GRE header's protocol type, an IPIP inner total length, a 6in4 flow label.
|
||||
// Reading them as ports would let a `proto: any` rule with a port match tunneled traffic.
|
||||
func Test_newPacket_v4NoPorts(t *testing.T) {
|
||||
p := &firewall.ParsedPacket{}
|
||||
|
||||
for _, proto := range []uint8{4, 41, 47, 50, 51, 132} { // IPIP, 6in4, GRE, ESP, AH, SCTP
|
||||
h := ipv4.Header{
|
||||
Version: 4,
|
||||
Len: ipv4.HeaderLen,
|
||||
Protocol: int(proto),
|
||||
Src: net.IPv4(10, 0, 0, 1),
|
||||
Dst: net.IPv4(10, 0, 0, 2),
|
||||
}
|
||||
b, err := h.Marshal()
|
||||
require.NoError(t, err)
|
||||
b = append(b, []byte{0x00, 0x00, 0x86, 0xdd}...) // a GRE header carrying IPv6 would read as port 34525
|
||||
|
||||
for _, incoming := range []bool{true, false} {
|
||||
require.NoError(t, newPacket(b, incoming, p))
|
||||
assert.Equal(t, proto, p.Protocol)
|
||||
assert.Equal(t, uint16(0), p.RemotePort)
|
||||
assert.Equal(t, uint16(0), p.LocalPort)
|
||||
assert.False(t, p.Fragment)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_newPacket_v6(t *testing.T) {
|
||||
p := &firewall.ParsedPacket{}
|
||||
|
||||
|
||||
Reference in new issue
Block a user