diff --git a/CHANGES b/CHANGES index 165491fe89..ac85924510 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,21 @@ +2.0-184 | 2012-03-28 15:11:11 -0700 + + * Improve handling of IPv6 Routing Type 0 headers. (Jon Siwek) + + - For RH0 headers with non-zero segments left, a + "routing0_segleft" flow_weird event is raised (with a + destination indicating the last address in the routing header), + and an "rh0_segleft" event can also be handled if the other + contents of the packet header are of interest. No further + analysis is done as the complexity required to correctly + identify destination endpoints of connections doesn't seem worth + it as RH0 has been deprecated by RFC 5095. + + - For RH0 headers without any segments left, a "routing0_header" + flow_weird event is raised, but further analysis still occurs as + normal. + 2.0-182 | 2012-03-28 15:01:57 -0700 * Remove dead tcp_checksum function from net_util. (Jon Siwek) diff --git a/VERSION b/VERSION index 9216c55c7e..aa1c74565c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.0-182 +2.0-184 diff --git a/src/IP.cc b/src/IP.cc index 4148c58a33..7f616fbbb0 100644 --- a/src/IP.cc +++ b/src/IP.cc @@ -305,6 +305,24 @@ void IPv6_Hdr_Chain::Init(const struct ip6_hdr* ip6, bool set_next, uint16 next) chain.push_back(p); + // RFC 5095 deprecates routing type 0 headers, so raise weirds for that. + if ( current_type == IPPROTO_ROUTING && + ((const struct ip6_rthdr*)hdrs)->ip6r_type == 0 ) + { + IPAddr src(((const struct ip6_hdr*)(chain[0]->Data()))->ip6_src); + + if ( ((const struct ip6_rthdr*)hdrs)->ip6r_segleft > 0 ) + { + const in6_addr* a = (const in6_addr*)(hdrs+len-16); + reporter->Weird(src, *a, "routing0_segleft"); + } + else + { + IPAddr dst(((const struct ip6_hdr*)(chain[0]->Data()))->ip6_dst); + reporter->Weird(src, dst, "routing0_header"); + } + } + hdrs += len; length += len; } while ( current_type != IPPROTO_FRAGMENT && diff --git a/src/IP.h b/src/IP.h index cb5bcf77c7..daa508db7f 100644 --- a/src/IP.h +++ b/src/IP.h @@ -171,6 +171,20 @@ public: { return IsFragment() ? (ntohs(GetFragHdr()->ip6f_offlg) & 0x0001) != 0 : 0; } + /** + * Returns whether the chain contains a routing type 0 extension header + * with nonzero segments left. + */ + bool RH0SegLeft() const + { + for ( size_t i = 0; i < chain.size(); ++i ) + if ( chain[i]->Type() == IPPROTO_ROUTING && + ((const struct ip6_rthdr*)chain[i]->Data())->ip6r_type == 0 && + ((const struct ip6_rthdr*)chain[i]->Data())->ip6r_segleft > 0 ) + return true; + return false; + } + /** * Returns a vector of ip6_ext_hdr RecordVals that includes script-layer * representation of all extension headers in the chain. @@ -343,6 +357,13 @@ public: size_t NumHeaders() const { return ip4 ? 1 : ip6_hdrs->Size(); } + /** + * Returns true if this is an IPv6 header containing a routing type 0 + * extension with nonzero segments left, else returns false. + */ + bool RH0SegLeft() const + { return ip4 ? false : ip6_hdrs->RH0SegLeft(); } + /** * Returns an ip_hdr or ip6_hdr_chain RecordVal. */ diff --git a/src/Sessions.cc b/src/Sessions.cc index 84b57bdc62..9ab7d1d1fa 100644 --- a/src/Sessions.cc +++ b/src/Sessions.cc @@ -481,6 +481,22 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, return; } + // Stop analyzing IPv6 packets that use routing type 0 headers with segments + // left since RH0 headers are deprecated by RFC 5095 and we'd have to make + // extra effort to get the destination in the connection/flow endpoint right. + if ( ip_hdr->RH0SegLeft() ) + { + dump_this_packet = 1; + if ( rh0_segleft ) + { + val_list* vl = new val_list(); + vl->append(ip_hdr->BuildPktHdrVal()); + mgr.QueueEvent(rh0_segleft, vl); + } + Remove(f); + return; + } + int proto = ip_hdr->NextProto(); if ( CheckHeaderTrunc(proto, len, caplen, hdr, pkt) ) diff --git a/src/event.bif b/src/event.bif index 113c003e37..20714c0931 100644 --- a/src/event.bif +++ b/src/event.bif @@ -478,6 +478,14 @@ event ipv6_ext_headers%(c: connection, p: pkt_hdr%); ## .. bro:see:: new_packet tcp_packet ipv6_ext_headers event esp_packet%(p: pkt_hdr%); +## Generated for any packets using an IPv6 Routing Type 0 extension header +## with non-zero segments left. +## +## p: Information from the header of the packet that triggered the event. +## +## .. bro:see:: new_packet tcp_packet ipv6_ext_headers +event rh0_segleft%(p: pkt_hdr%); + ## Generated for every packet that has non-empty transport-layer payload. This is a ## very low-level and expensive event that should be avoided when at all possible. ## It's usually infeasible to handle when processing even medium volumes of diff --git a/testing/btest/Baseline/core.ipv6_ext_headers/output b/testing/btest/Baseline/core.ipv6_ext_headers/output index a5a0caf7c6..58332ca900 100644 --- a/testing/btest/Baseline/core.ipv6_ext_headers/output +++ b/testing/btest/Baseline/core.ipv6_ext_headers/output @@ -1 +1 @@ -[ip=, ip6=[class=0, flow=0, len=59, nxt=0, hlim=64, src=2001:4f8:4:7:2e0:81ff:fe52:ffff, dst=2001:4f8:4:7:2e0:81ff:fe52:9a6b, exts=[[id=0, hopopts=[nxt=43, len=0, options=[[otype=1, len=4, data=\0\0\0\0]]], dstopts=, routing=, fragment=, ah=, esp=], [id=43, hopopts=, dstopts=, routing=[nxt=17, len=4, rtype=0, segleft=2, data=\0\0\0\0 ^A\0x\0^A\02\0\0\0\0\0\0\0^A ^A\0x\0^A\02\0\0\0\0\0\0\0^B], fragment=, ah=, esp=]]], tcp=, udp=[sport=53/udp, dport=53/udp, ulen=11], icmp=] +[ip=, ip6=[class=0, flow=0, len=68, nxt=0, hlim=64, src=2001:4f8:4:7:2e0:81ff:fe52:ffff, dst=2001:4f8:4:7:2e0:81ff:fe52:9a6b, exts=[[id=0, hopopts=[nxt=43, len=0, options=[[otype=1, len=4, data=\0\0\0\0]]], dstopts=, routing=, fragment=, ah=, esp=], [id=43, hopopts=, dstopts=, routing=[nxt=6, len=4, rtype=0, segleft=0, data=\0\0\0\0 ^A\0x\0^A\02\0\0\0\0\0\0\0^A ^A\0x\0^A\02\0\0\0\0\0\0\0^B], fragment=, ah=, esp=]]], tcp=[sport=30000/tcp, dport=80/tcp, seq=0, ack=0, hl=20, dl=0, flags=2, win=8192], udp=, icmp=] diff --git a/testing/btest/Baseline/core.ipv6_rh0/segleft.out b/testing/btest/Baseline/core.ipv6_rh0/segleft.out new file mode 100644 index 0000000000..3c722ee3b4 --- /dev/null +++ b/testing/btest/Baseline/core.ipv6_rh0/segleft.out @@ -0,0 +1,2 @@ +flow_weird routing0_segleft from 2001:4f8:4:7:2e0:81ff:fe52:ffff to 2001:78:1:32::2 +rh0 w/ segments left from 2001:4f8:4:7:2e0:81ff:fe52:ffff to 2001:4f8:4:7:2e0:81ff:fe52:9a6b diff --git a/testing/btest/Baseline/core.ipv6_rh0/segleft0.out b/testing/btest/Baseline/core.ipv6_rh0/segleft0.out new file mode 100644 index 0000000000..ae57c7cc8d --- /dev/null +++ b/testing/btest/Baseline/core.ipv6_rh0/segleft0.out @@ -0,0 +1,2 @@ +flow_weird routing0_header from 2001:4f8:4:7:2e0:81ff:fe52:ffff to 2001:4f8:4:7:2e0:81ff:fe52:9a6b +new_connection: [orig_h=2001:4f8:4:7:2e0:81ff:fe52:ffff, orig_p=30000/tcp, resp_h=2001:4f8:4:7:2e0:81ff:fe52:9a6b, resp_p=80/tcp] diff --git a/testing/btest/Traces/ext_hdr_hbh_routing.trace b/testing/btest/Traces/ipv6-hbh-rh0-segleft.trace similarity index 100% rename from testing/btest/Traces/ext_hdr_hbh_routing.trace rename to testing/btest/Traces/ipv6-hbh-rh0-segleft.trace diff --git a/testing/btest/Traces/ipv6-hbh-rh0-segleft0.trace b/testing/btest/Traces/ipv6-hbh-rh0-segleft0.trace new file mode 100644 index 0000000000..35f5b3afe6 Binary files /dev/null and b/testing/btest/Traces/ipv6-hbh-rh0-segleft0.trace differ diff --git a/testing/btest/bifs/routing0_data_to_addrs.test b/testing/btest/bifs/routing0_data_to_addrs.test index 4bf15cae87..de10dd80e0 100644 --- a/testing/btest/bifs/routing0_data_to_addrs.test +++ b/testing/btest/bifs/routing0_data_to_addrs.test @@ -1,7 +1,7 @@ -# @TEST-EXEC: bro -C -b -r $TRACES/ext_hdr_hbh_routing.trace %INPUT >output +# @TEST-EXEC: bro -b -r $TRACES/ipv6-hbh-rh0-segleft.trace %INPUT >output # @TEST-EXEC: btest-diff output -event ipv6_ext_headers(c: connection, p: pkt_hdr) +event rh0_segleft(p: pkt_hdr) { for ( h in p$ip6$exts ) if ( p$ip6$exts[h]$id == IPPROTO_ROUTING ) diff --git a/testing/btest/core/ipv6_ext_headers.test b/testing/btest/core/ipv6_ext_headers.test index 170a67bc72..0cf3f2f3fb 100644 --- a/testing/btest/core/ipv6_ext_headers.test +++ b/testing/btest/core/ipv6_ext_headers.test @@ -1,4 +1,4 @@ -# @TEST-EXEC: bro -C -b -r $TRACES/ext_hdr_hbh_routing.trace %INPUT >output +# @TEST-EXEC: bro -b -r $TRACES/ipv6-hbh-rh0-segleft0.trace %INPUT >output # @TEST-EXEC: btest-diff output # Just check that the event is raised correctly for a packet containing diff --git a/testing/btest/core/ipv6_rh0.test b/testing/btest/core/ipv6_rh0.test new file mode 100644 index 0000000000..18c23ed3b7 --- /dev/null +++ b/testing/btest/core/ipv6_rh0.test @@ -0,0 +1,22 @@ +# @TEST-EXEC: bro -b -r $TRACES/ipv6-hbh-rh0-segleft0.trace %INPUT >segleft0.out +# @TEST-EXEC: btest-diff segleft0.out +# @TEST-EXEC: bro -b -r $TRACES/ipv6-hbh-rh0-segleft.trace %INPUT >segleft.out +# @TEST-EXEC: btest-diff segleft.out + +# This will be raised only by the packet with RH0 and segments left. +event rh0_segleft(p: pkt_hdr) + { + print fmt("rh0 w/ segments left from %s to %s", p$ip6$src, p$ip6$dst); + } + +# This will be raised only by the packet with RH0 and no segments left. +event new_connection(c: connection) + { + print fmt("new_connection: %s", c$id); + } + +# This will be raised by any packet with RH0 regardless of segments left. +event flow_weird(name: string, src: addr, dst: addr) + { + print fmt("flow_weird %s from %s to %s", name, src, dst); + }