From 7717a3eb674f07ae7a1920b829dcfbcfeacbd257 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Thu, 16 Jan 2014 16:03:04 -0600 Subject: [PATCH 1/2] BIT-867 - Support GRE tunnel decapsulation. This includes enhanced GRE headers. GRE tunnels are treated just like IP-in-IP tunnels by parsing past the GRE header in between the delivery and payload IP packets. --- scripts/base/init-bare.bro | 6 +- src/Sessions.cc | 123 ++++++++++++++++++ src/const.bif | 1 + .../Baseline/core.tunnels.gre-in-gre/conn.log | 12 ++ .../core.tunnels.gre-in-gre/tunnel.log | 11 ++ .../btest/Baseline/core.tunnels.gre/conn.log | 16 +++ .../btest/Baseline/core.tunnels.gre/dns.log | 11 ++ .../btest/Baseline/core.tunnels.gre/ssh.log | 10 ++ .../Baseline/core.tunnels.gre/tunnel.log | 10 ++ testing/btest/Traces/tunnels/gre-sample.pcap | Bin 0 -> 7395 bytes .../btest/Traces/tunnels/gre-within-gre.pcap | Bin 0 -> 111736 bytes testing/btest/core/tunnels/gre-in-gre.test | 3 + testing/btest/core/tunnels/gre.test | 5 + 13 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 testing/btest/Baseline/core.tunnels.gre-in-gre/conn.log create mode 100644 testing/btest/Baseline/core.tunnels.gre-in-gre/tunnel.log create mode 100644 testing/btest/Baseline/core.tunnels.gre/conn.log create mode 100644 testing/btest/Baseline/core.tunnels.gre/dns.log create mode 100644 testing/btest/Baseline/core.tunnels.gre/ssh.log create mode 100644 testing/btest/Baseline/core.tunnels.gre/tunnel.log create mode 100644 testing/btest/Traces/tunnels/gre-sample.pcap create mode 100644 testing/btest/Traces/tunnels/gre-within-gre.pcap create mode 100644 testing/btest/core/tunnels/gre-in-gre.test create mode 100644 testing/btest/core/tunnels/gre.test diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index 9f8c9f42ac..8d4899b785 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -3057,6 +3057,9 @@ export { ## Toggle whether to do GTPv1 decapsulation. const enable_gtpv1 = T &redef; + ## Toggle whether to do GRE decapsulation. + const enable_gre = T &redef; + ## With this option set, the Teredo analysis will first check to see if ## other protocol analyzers have confirmed that they think they're ## parsing the right protocol and only continue with Teredo tunnel @@ -3082,7 +3085,8 @@ export { ## may work better. const delay_gtp_confirmation = F &redef; - ## How often to cleanup internal state for inactive IP tunnels. + ## How often to cleanup internal state for inactive IP tunnels + ## (includes GRE tunnels). const ip_tunnel_timeout = 24hrs &redef; } # end export module GLOBAL; diff --git a/src/Sessions.cc b/src/Sessions.cc index 7d497adf77..cc5e48a9b5 100644 --- a/src/Sessions.cc +++ b/src/Sessions.cc @@ -376,6 +376,31 @@ int NetSessions::CheckConnectionTag(Connection* conn) return 1; } +static unsigned int gre_header_len(uint16 flags) + { + unsigned int len = 4; // Always has 2 byte flags and 2 byte protocol type. + + if ( flags & 0x8000 ) + // Checksum/Reserved1 present. + len += 4; + + // Not considering routing presence bit since it's deprecated... + + if ( flags & 0x2000 ) + // Key present. + len += 4; + + if ( flags & 0x1000 ) + // Sequence present. + len += 4; + + if ( flags & 0x0080 ) + // Acknowledgement present. + len += 4; + + return len; + } + void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, const IP_Hdr* ip_hdr, const u_char* const pkt, int hdr_size, const EncapsulationStack* encapsulation) @@ -562,6 +587,101 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, break; } + case IPPROTO_GRE: + { + if ( ! BifConst::Tunnel::enable_gre ) + { + Weird("GRE_tunnel", ip_hdr, encapsulation); + Remove(f); + return; + } + + uint16 flags_ver = ntohs(*((uint16*)(data + 0))); + uint16 proto_typ = ntohs(*((uint16*)(data + 2))); + int gre_version = flags_ver & 0x0007; + + if ( gre_version != 0 && gre_version != 1 ) + { + Weird(fmt("unknown_gre_version_%d", gre_version), ip_hdr, + encapsulation); + Remove(f); + return; + } + + if ( gre_version == 0 ) + { + if ( proto_typ != 0x0800 && proto_typ != 0x86dd ) + { + // Not IPv4/IPv6 payload. + Weird(fmt("unknown_gre_protocol_%"PRIu16, proto_typ), ip_hdr, + encapsulation); + Remove(f); + return; + } + + proto = (proto_typ == 0x0800) ? IPPROTO_IPV4 : IPPROTO_IPV6; + } + else // gre_version == 1 + { + if ( proto_typ != 0x880b) + { + // Enhanced GRE payload must be PPP. + Weird("egre_protocol_type", ip_hdr, encapsulation); + Remove(f); + return; + } + } + + if ( flags_ver & 0x4000 ) + { + // RFC 2784 deprecates the variable length routing field + // specified by RFC 1701. It could be parsed here, but easiest + // to just skip for now. + Weird("gre_routing", ip_hdr, encapsulation); + Remove(f); + return; + } + + if ( flags_ver & 0x0078 ) + { + // Expect last 4 bits of flags are reserved, undefined. + Weird("unknown_gre_flags", ip_hdr, encapsulation); + Remove(f); + return; + } + + unsigned int gre_len = gre_header_len(flags_ver); + unsigned int ppp_len = gre_version == 1 ? 1 : 0; + + if ( len < gre_len + ppp_len || caplen < gre_len + ppp_len ) + { + Weird("truncated_GRE", ip_hdr, encapsulation); + Remove(f); + return; + } + + if ( gre_version == 1 ) + { + int ppp_proto = *((uint8*)(data + gre_len)); + + if ( ppp_proto != 0x0021 && ppp_proto != 0x0057 ) + { + Weird("non_ip_packet_in_egre", ip_hdr, encapsulation); + Remove(f); + return; + } + + proto = (ppp_proto == 0x0021) ? IPPROTO_IPV4 : IPPROTO_IPV6; + } + + data += gre_len + ppp_len; + len -= gre_len + ppp_len; + caplen -= gre_len + ppp_len; + + // Treat GRE tunnel like IP tunnels, fallthrough to logic below now + // that GRE header is stripped and only payload packet remains. + } + case IPPROTO_IPV4: case IPPROTO_IPV6: { @@ -822,6 +942,9 @@ bool NetSessions::CheckHeaderTrunc(int proto, uint32 len, uint32 caplen, case IPPROTO_NONE: min_hdr_len = 0; break; + case IPPROTO_GRE: + min_hdr_len = 4; + break; case IPPROTO_ICMP: case IPPROTO_ICMPV6: default: diff --git a/src/const.bif b/src/const.bif index a45dfb0a7a..fd0419c7d9 100644 --- a/src/const.bif +++ b/src/const.bif @@ -17,6 +17,7 @@ const Tunnel::enable_ip: bool; const Tunnel::enable_ayiya: bool; const Tunnel::enable_teredo: bool; const Tunnel::enable_gtpv1: bool; +const Tunnel::enable_gre: bool; const Tunnel::yielding_teredo_decapsulation: bool; const Tunnel::delay_teredo_confirmation: bool; const Tunnel::delay_gtp_confirmation: bool; diff --git a/testing/btest/Baseline/core.tunnels.gre-in-gre/conn.log b/testing/btest/Baseline/core.tunnels.gre-in-gre/conn.log new file mode 100644 index 0000000000..6da1bd2132 --- /dev/null +++ b/testing/btest/Baseline/core.tunnels.gre-in-gre/conn.log @@ -0,0 +1,12 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open 2014-01-16-21-51-36 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string bool count string count count count count table[string] +1341436440.002928 CRJuHdVW0XPVINV8a 3.3.3.2 520 224.0.0.9 520 udp - 26.148268 48 0 S0 - 0 D 2 104 0 0 CjhGID4nQcgTWjvg4c +1341436424.378840 CsRx2w45OKnoww6xl4 3.3.3.1 520 224.0.0.9 520 udp - 28.555457 168 0 S0 - 0 D 2 224 0 0 CjhGID4nQcgTWjvg4c +1341436424.204043 CCvvfg3TEfuqmmG4bh 10.10.25.1 8 192.168.1.2 0 icmp - 42.380221 22464 22464 OTH - 0 - 312 31200 312 31200 CjhGID4nQcgTWjvg4c +#close 2014-01-16-21-51-36 diff --git a/testing/btest/Baseline/core.tunnels.gre-in-gre/tunnel.log b/testing/btest/Baseline/core.tunnels.gre-in-gre/tunnel.log new file mode 100644 index 0000000000..277d1df679 --- /dev/null +++ b/testing/btest/Baseline/core.tunnels.gre-in-gre/tunnel.log @@ -0,0 +1,11 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path tunnel +#open 2014-01-16-21-51-36 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p tunnel_type action +#types time string addr port addr port enum enum +1341436424.204043 CXWv6p3arKYeMETxOg 72.205.54.70 0 86.106.164.150 0 Tunnel::IP Tunnel::DISCOVER +1341436424.204043 CjhGID4nQcgTWjvg4c 10.10.11.2 0 10.10.13.2 0 Tunnel::IP Tunnel::DISCOVER +#close 2014-01-16-21-51-36 diff --git a/testing/btest/Baseline/core.tunnels.gre/conn.log b/testing/btest/Baseline/core.tunnels.gre/conn.log new file mode 100644 index 0000000000..b29d87f40a --- /dev/null +++ b/testing/btest/Baseline/core.tunnels.gre/conn.log @@ -0,0 +1,16 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open 2014-01-16-21-51-12 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string bool count string count count count count table[string] +1055289978.756932 CsRx2w45OKnoww6xl4 66.59.111.190 40264 172.28.2.3 22 tcp ssh 3.157831 952 1671 SF - 0 ShAdDaFf 12 1584 10 2199 CXWv6p3arKYeMETxOg +1055289987.055189 CRJuHdVW0XPVINV8a 66.59.111.190 37675 172.28.2.3 53 udp dns 5.001141 66 0 S0 - 0 D 2 122 0 0 CXWv6p3arKYeMETxOg +1055289996.849099 CIPOse170MGiRM1Qf4 66.59.111.190 123 129.170.17.4 123 udp - 0.072374 48 48 SF - 0 Dd 1 76 1 76 CXWv6p3arKYeMETxOg +1055289973.849878 CCvvfg3TEfuqmmG4bh 66.59.111.190 123 18.26.4.105 123 udp - 0.074086 48 48 SF - 0 Dd 1 76 1 76 CXWv6p3arKYeMETxOg +1055289992.849231 C6pKV8GSxOnSLghOa 66.59.111.190 123 66.59.111.182 123 udp - 0.056629 48 48 SF - 0 Dd 1 76 1 76 CXWv6p3arKYeMETxOg +1055289968.793044 CjhGID4nQcgTWjvg4c 66.59.111.190 8 172.28.2.3 0 icmp - 3.061298 224 224 OTH - 0 - 4 336 4 336 CXWv6p3arKYeMETxOg +1055289987.106744 CPbrpk1qSsw6ESzHV4 172.28.2.3 3 66.59.111.190 3 icmp - 4.994662 122 0 OTH - 0 - 2 178 0 0 CXWv6p3arKYeMETxOg +#close 2014-01-16-21-51-12 diff --git a/testing/btest/Baseline/core.tunnels.gre/dns.log b/testing/btest/Baseline/core.tunnels.gre/dns.log new file mode 100644 index 0000000000..2b8b9fc6ab --- /dev/null +++ b/testing/btest/Baseline/core.tunnels.gre/dns.log @@ -0,0 +1,11 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path dns +#open 2014-01-16-21-51-12 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto trans_id query qclass qclass_name qtype qtype_name rcode rcode_name AA TC RD RA Z answers TTLs rejected +#types time string addr port addr port enum count string count string count string count string bool bool bool bool count vector[string] vector[interval] bool +1055289987.055189 CRJuHdVW0XPVINV8a 66.59.111.190 37675 172.28.2.3 53 udp 48554 www.gleeble.org 1 C_INTERNET 255 * - - F F T F 0 - - F +1055289992.056330 CRJuHdVW0XPVINV8a 66.59.111.190 37675 172.28.2.3 53 udp 48554 www.gleeble.org 1 C_INTERNET 255 * - - F F T F 0 - - F +#close 2014-01-16-21-51-12 diff --git a/testing/btest/Baseline/core.tunnels.gre/ssh.log b/testing/btest/Baseline/core.tunnels.gre/ssh.log new file mode 100644 index 0000000000..5b05545bd0 --- /dev/null +++ b/testing/btest/Baseline/core.tunnels.gre/ssh.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ssh +#open 2014-01-16-21-51-12 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p status direction client server +#types time string addr port addr port string enum string string +1055289978.855137 CsRx2w45OKnoww6xl4 66.59.111.190 40264 172.28.2.3 22 failure INBOUND SSH-2.0-OpenSSH_3.6.1p1 SSH-1.99-OpenSSH_3.1p1 +#close 2014-01-16-21-51-12 diff --git a/testing/btest/Baseline/core.tunnels.gre/tunnel.log b/testing/btest/Baseline/core.tunnels.gre/tunnel.log new file mode 100644 index 0000000000..f0d87f4964 --- /dev/null +++ b/testing/btest/Baseline/core.tunnels.gre/tunnel.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path tunnel +#open 2014-01-16-21-51-12 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p tunnel_type action +#types time string addr port addr port enum enum +1055289968.793044 CXWv6p3arKYeMETxOg 172.27.1.66 0 66.59.109.137 0 Tunnel::IP Tunnel::DISCOVER +#close 2014-01-16-21-51-12 diff --git a/testing/btest/Traces/tunnels/gre-sample.pcap b/testing/btest/Traces/tunnels/gre-sample.pcap new file mode 100644 index 0000000000000000000000000000000000000000..31c08b6ba4761ebcb5fe702c9854a43d2e586b62 GIT binary patch literal 7395 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 Ezmr7m6951J literal 0 HcmV?d00001 diff --git a/testing/btest/Traces/tunnels/gre-within-gre.pcap b/testing/btest/Traces/tunnels/gre-within-gre.pcap new file mode 100644 index 0000000000000000000000000000000000000000..c0a8d5c41beb6962fbc3ee638815cf2b166521d1 GIT binary patch literal 111736 zcmb{52apxjw#M-@LmF~aa?XNe5G6;EoCHK9NKT3(K>)wU7PtO161h|KkEu?rQ|%SMlFcc8E~``PRO`h~ty3L| z9JO9NBOfa^H$F?oErsz0GJb{`*MRX~%J_0P;V%z3#;0~Ch%Co%==>B{#T<22WPa?b zh>eWQ|GQJ%dCX(Qv5{WRZxWsQ$jW%};zgZ_L=s2G;KFD%?{qZ23K9HFoH%hL&bcVv zAJNXQ;rDQU?ScBWDEHSg@_&wgEnT{FkNtB_{mndyo^*wbr7L8LxI(hi6_Q0m*NC5H@?smtF+Gwz$#^Ome=3X% zka1dJtcnBUgVu{P_GQK9#@ETXfiT`q#yJAxo&Ui2p?e*FR@jDds$t2VWIT zaVlY~iUZ^Q){C>e!-~y~|0LtO!gv=MW1I6w>;zRhhQA#8c%I#!+6PfwsT73S!DdN zFn*SdQwU>K92oDjUK~4v6`LF1BIDY^_-u2SQRs4>%~!Duwrv#JTt%(hL?o#9x}$dm}-cQC@w|wJ#Fixn9?}Rl@ihH+TFcIQ^>F58m zZQ|d;Uh$DIEDV|9mdbzyvvjInO{#u;E7;~LM5*tm{A z`I;?-(s%(G4;99x$T*QOR>jQNdhwPmtk~Qbt2>OV3FAX#jCIR1-ZB=(iIs8ajo!JA zGwx(dp)_7d#vcgd(qx=a7^~vIc(?W9tcO^!xiMCE7*`d>hshZ0mT#O8#z|b`S)n(2 z$N1`DwiHU^FUWX^FfK#J352mKX2#ZwH~++n&5g0T!?=ntK0?M=w>;zTK7esjWjx8o zYsJ!2Y$=q+i^zDeFn*4V;|pU|92oDiUOe-6R%~vJ)g8u_h4Bw$jCIR1{`LWklexyT zGuSY`e~vAM(s(f$zb}l-l5sp?tcnBUoz{!b{=tgPjj_7JxRNkFO2$~XeB<6QPOgmS z*f8$;4_gYQ@e(o~B#fUYW4v2TdncJHX2#ZwUyDi^+-;g0V|9mdMPYo5jInNc#+$Fg zIE8Ecd4aIT$?$r-b30oKrSVcS9w>}oAmb=utcnBU9oCBvA7I7i##r59TtOHgCu6Kz zzHvJkr&Pu(Z5R*Q$Cg5A{3RI=5XR-m81J;xu47fqjI9?hInIjBjj_7JxV$hvLB?3O zJmXELVVue}o>R((anh4)DU`)O#3ge&180(g2ykRqp)49g;LO*MAjNeQ5#Cx}uWZYL6S0>~C31d|p7;m*+JQO!p z{!(aejMW{+&k5t7$r$UFZ~PpLpHjxh!oF4{hjH0+Y$=r2@hURzBaEw%@qJ;eikY$X z;--JFVsm4x?l3MRj8Bs>)-BI?J>Jcm?P=F|e&}aSj`7B;Y$=q+tI7BsVO*7r{}sln zI53X2UVQWpD>gUA>JH=5!uS_5#=7Mj7ld(oWqiiQb-X5yErrr}4H@?q#?{F9o-kI$ z%-DW$;{SB-hSeR$rG)XXWQ=voGhR0n#u;4W1)-lcIoI*B4D3!w8m}eew}o+aGX6&x ztKz_Ti}m8gxmdCJb&S;=#wCUEZ)A*h%QsF7gtwclL|xvSM>%tnM%_E{xBTF?|-&sg8+!69wbUuJIS4KM&#<=WooO@=D`% zWc;Quevypt2xC>ujI9?JY{iPrjj_7JxR@~hos6+=dDrpR{b8I%8IKP8XI=^zZ_UH* zgrxC$GJZoC*COM;gt00PjK8&ByrT#!HaEuV4&$Q2827IDBr?`5&v@;hFwW{4FG^>_ z_{B2pPDmPWAmg6G_$4yFEsRxhV7%FSafK?Z*xVSaJB*76$75WW328lepVP?AY-gsp7EMrV4U4GUYy5< z@s-x>DX+YaH<597VO)odZwg~o92jr1UVO0&D>gUA>JH<=!uTQ?W8LzNo5DDUGG1oG zIQnh&lvf&WCgX0xxGow0DU4MyGqzrwcpxh_H^%A?W1Ik?oeXh_jInNc#;feHizAlVaabUc`dhy1Etk~Qbt2>NwhJtn-UnOI# zTfT8A7~_uC`8>$d&>MY97`N=hp7KiLSTgP;j2n{iHDRoZnX&caqJvqnxiMCE7~>2D z&G;G_W8LzMS1y8aUf1}`reR+z9OGdhv!}e$cq&2@kvSM>% ztnM(z848;5buz}fL~6f|Qj{`flx)-BI?#WWb_ca4{|wPE~lK3fW<@pdw9FN~Xz@nvDGiUZ?y){CQ- zvtn~&tnM(z848;54Kl{M%zDx8DA2{s+bvDFK+)W zD>gUA>JDR^p`aQ6Nyb>WJmcjfU|i5O{;HP^<0E_6QYejgl5sm>{4yC|6vnDJF#g7R z@!g}W*xVSaJB)FLf@XY^jInNc#$P>x@iWT!o(<#WhuKmnjdzi8TVdRcj4uddRU8<9 zZN0eHPpsJ77^^#safX6se2a{+Zu!RV!nlxYygc+qp9=RC^QW<;P#W(h<2J&$IT@c9 z#;TYZTQ5E^pB0-MV|9ly&QQ>dZ<8_BEzfw_O&Aw;jaP);=pExBOW0BjMW{+I72}*{)>#UZu!RDVf?Hz9vSwv!ZEJ9iYL~6g1;IWQ=voGyd{-7#DGkSBCyPh+|x4KU)f= z@m?}+C5&5=@mXQ4iUZ>{){B##V8!OfSlwZaGZZxAyJU=Y%Qt=n#zmF!R2$cE!&7W2 zl*aqW_*G&2DjA;<#;TYZTQ6?@J1aIf#_A4ZoS~o@|4qhNw>;yehhbdIHC~m&hVjP_ z*itBs_mgo;Vcd$0e-p;4I51vqy?AcI|8(z`gN$*8f@b^=8Drh@jjO@9xH1mC(L1jd zTb^cjLelsE8NVWoUnApRg|RAT#@36c%UVOUgUA>JDR^p`aQ6OU78YeB9CaoxLYDU`;C$+(#?ZcD~L3u9Fr7_YQmoHvdYn;TSVt&Br&^p5fA1nf>o8XqC!mxXaVGX6;zt72wsz4&}eR%~vJ)g8t-LqRis zK*m_NJmW>PVO+*FUR&43b(}IayAzVeKag=#Vf;E7|0s-AabUc{dU4^*tk~Qbt2>Nw zhJt4Nkc_cz`NmJd_&H^K%!cvw%ul>`J4(h)gmHT^J|&D*F*CMa+&wQVHaEuV4r835 zpcy|RW2{@A@fYJ@T-G)Ix`hqn@&(vaUU?lKBjd)xxC0rV6vnDJFkWuGxJwCEY;KIz z9mY6AK{JjcW2{@gaUvK$uZ%;#kKTDbPF;yT<(0LKEXJL0j()c79HxS01$@rKs zR>gtwGV8^e^Rr@eW328l#u*BlaWolY-SUllz_`3?ysp0u;}?pvr@Yem6dBhS#$Cwx zs4!N=%-DKyopP+$+!(7njB$p7W*m=gUA>JDR^p`aNjB4eyup7Gr6Fs|YnZ_E`|gzmf5a!uU-x-Y<+*abUdIdU3`6tk~Qbt2>NigmDrw#=7Mj7l3hfWxUpg z@xv)>DU`-%$e6z8=40Q*vKJZe6UM5T8QU+O%Zkm7vAV+;XDDc|6-mh$>y~Hy`4kw} zaE&*IejmN_dfa^;TMDJ|Su(C6uH(1Jc&{*4#ewl6>&4@iv0`&$tnM(z848+lGBU=x zqFjmFP*n07Z^{m+37^^#safX6soSclY zZh6MDKZfy(uJN}GZM;_W+Q61VX?%{1s|n-YWcgtw7uJj4+0Kg1jj_7J7-uMG z#wo}c>y~dEAI7zmap;ZSxsDU>WJ{qmK2OF~h4DLNyjvKnVrFc;IQ1b`Y;KIz9mY6A zK{HNC##pyJ<5>e>{E}<@U8}IyaXJ`x{E97w()a=yR}sd2$at49R>gtwLhHrl*Rf)A zW328l#u*BlaVj##y5$+qyaD6d%J{Mk<0aeKQYeitl5u5W+?R}Z3S(6q7%#A1yzc-j zHaEuV4r835pc$toW2{@gaYq=}agDe1vSHkLKU)f=@g*{@B#ir!@eX0EikY$X;^ik; zvAHo;cNpUg1y~fa1jbkxoX^ zL~6g1 zFmCJ`Z_i=FIP-0`6iVY8WL#DlzfZ>B3S(6q7|*d@{MrLnY;IhYjB$p7W}K0Xv2OXs zd12f{8He8Jo!5$%so0&6H2#x}pA*J|$#}CcR>jQNdhvivtk~Qbt2?e^oS~o@XCh;) zTb}WhnJ{kZ8t*7(<2p`>Z%yRCx=G`kWL!oV4tdX7^g1Gp7KiLTVz~X7=J*<8-=kdX2#Zw^ORx5=EhjvVT>~r zG~+B}jCIR1{>(YOvYBhVv$752-DTNRUTJ)rj7tgQp=7*47^~vIc((Q8165hExiMCE z7~>2D%{VI=W8LzN6TrB+GTsr^_-VWzkHz19pYU4o7a5ln#vhXLdSR@JnX&caDfl}2 z#pcFX-C>L~6g1;(WQ=voGoI|6UfIGm-W7VIcZ`qaWOqXHI=(~3C4})uWV}uotKz_T zmi6NMg;=q~rG~--kjCIR5c22Ksd^O7;vEzfxT1{k+-jrYcc zeLYSO<3@wnQ(kHOKQb;Pj6WgcmBLsR2gcK^7k3`Pip`C&y2BV}C}_s{$QbLEZ(JD0 zZIyB8_a8gPCq}TRywdmq89yV8N0adiVXTUovGwAI<5{t}F;;gN;|vAOI6oO<-SUjb z&4+P2*LYv(_a8gPDQ2*zywdm~85b1BW5{^9FjmEZ@l@-@ITx~Gb7QRTFvb}QnsEU# z#=7MjXM*wT%6Nf|*NSQL*itBsACYkZVf-l>e(&M%C|lJPQOtcnBUDb|ZSoMgr3##r59d|4Pj zL&jLQeB&4xcTmQm-+%19R_yqhErr6^`QsJe&orMf9!JJs3S(8wjI9@ExX6mljj_7J z7-uMG*Kr{-#=7Mhe>xb(9bMxC zZj99(#yCSkGcHWVShqamG52BINg2n6HO_$RxL49hb3fBc+_*Bs%qxYw_a6i#`*HB#w^3H$ckK_-r(Op9p@!J`xv)7a;dXlv9xY zAloYCS2-RPRmQ&N zf0eu9tK8Wkil63S=ylaG9`GaEDy4CJGR`H8Cz0_YVXTUovGwA9=UB11F?N3#;}i$Y zxCj|zU-OJdpNDZ5WgPk)(2j9}OKhu@#tFzcr!byO#$O0yRU8;kvR<6?7ArP4#_kVe zoZ_Gv7bRotYrgTTFz)Ia9}2y$I>vc!v#nAZCnVz>!uT^XUMP%JF*CMa+~ol)HaEuZ z4`ZC-pcxkQN&A2!jV_)-)UxIOW*Z6P`8-MB+F39f1q;U)xXA{O#$#}jnR>jQNdU3y! ztk~QbyFZN22;&lDjD5{B9_74$t%ouWy{F9yUZ0W`n;T>IhcQlZ(2Q}%ixZ8ouX)BFJMUk6!!`aPz76Aqnc1C? zypD1Ij=yPU7REEkc#beu#ewm7>%~R$vSM>%?EWyuDGr)(X)?yX<{LZjUwcy-kG5gF zy#TutlE%r%IFm4*NyeWGV^z$Itrx#voE4iJW0-(3PI1tT%aAelHP3jY^ZvD7uJO^( z?|^n*D`HEtJ0WSDoQyLH<5^@pTNtb2z<8YX;!~AavAJ=#%|8;vSM@N*U9)tVf;K9 zV_)-)o%gTxcCX`Oq2B@RyjDEdnLTHg#;M5oX<wB;~-XS zZj9X@#yG`6GcHHQSP;GIc-UVs?xT!DzXLiGjBi$B&zYrh8Zu5NjBz{tsA!pK!dMjt z#$&7(->Aom&5g19!x*PHXvXEq7z?6r{05Bsy2d9$KP7OCD>rA)nWb@BGEOUu=acbN zVXTUovGw9^?O3t7F?N3#;}i$YxB?ktLG+A2x&Y&T%6LcEKl2>p-aXiJW@(&`jME6? z1!O!$7^~vIc(nE6S$$ctxiMCE7~>QN&A1{NV?p$dTfn%#YkV^FM(-G}>%*QiOXH`= zIJGcdNXDNDV^z$Itrwph%!yTaY|vlh>Rx*V^z$Itrxdi$coL4vAV+;r#NWFRmd0%qGvpGD~tyyMV95myqWQ+yTH!cg~fv)k7p*Q-> zF#aB|?#{01{QQ5m&5UH6To^AQ;|ao86*FV&#g~S%Vsm4x?l8tF4w`W_GRA`F8Go<> z#)Fjcov`;6j`66E*itC3<4k0nOc*aElu(826jVmO^Qqg^ZI3<7H$#Rv4?|z<8wf;xV&WvAHo;cNpUo2hF%9 z8Dl~8jkCabh->`wM>dT2&1OrXG|o!KiG}f3Wc;ZxR>jQNdhyZ4tk~Qbt2>Nwii2kS zA{k>r^o$2P=VyN48lMjRPJZY0c-hx%DU`<9$T&tAFDK(M!dMjt#v`m3uiwIo&5g0T z!x*PHXvVe37z?6roC3!9bJck-*6DFJuH(3!Y$=q+*~vJOFkV5%qlK|5X2#Zwvma)~ z=EhjvVT@B8G~<`Z7z?6j{QfW)f9M+jlEH>?jUU)jD2;QFaYA9dl8iqQ#;Q0l9&Ww( z&C{&d+!(7njB$#CW?Y+$u^@WJgC4;6BV{}%tZ^2+R%DpYmO^QqlZ+Dx<5grlN*Jr+ zz<8MT;-?p|Vsm4x?l8tF4w`WtGRA`F8~20pFxU9k(9fD2;{yxXQYejck#T%syqb(Z z7RIWW8Cx&@W(6xYH^%A?W1Qlk8P_FaEQp@*z#A|gu8f!2xQ=fgW=o+o&P~Sggz*|O z9x04fabWzB_2Pm*vtn~&tnM(zDGr)(Ju=3E=o`0#@d(%Wx3V^j`yt4SM9+A@DHxAb#-ZQI@4QwFzQmS7X`Gjg zqlEF-WIS9LtKz`;L+i!8Zn0u>W9%|8#wiY(aRV~Og6JDJf$_(#@tNv2uH$C$*`1Iy z&PT=(Vf+ml4->|!m>F9y{%s5^HaEuV4r83+pcywLV=RcC@q1suc$6}}X~X!yBz7kx zjq^Lk*W-loIx_x97^~vIc&PQ_8?#xlxiMCE7;hEEjmQ`aqHmlP#-F&xXG3p7S@Bv? zun)TvlEwwd_>nMPPsSe#V^z$ItrwRa%!_a6%5 zPhI14scabcox|>gq;VlK{+}@3M8-peu__LXhgdJ3vy>H^8)J2cF-~#Nj9(^WEQp?Q zzkgvoRvAyVVVrv-yAzVeg~|B7Fy2hYgN3mw4vYs|FRrnJ6`LDlb%!xdanOvLkuerT z-?$fy$GOJmbJ#GxdVoFUmB!DK@xQ|OTQYuM7^`AtY`r+sDOPN5JcNvKii2j{oQ$y` zdd7V(!Faqf4*kAO=g+(pzp|&i(zpm2-xJ2)k?|m5tcnBU_pKKfyUdEsjj_7pI>spu znsEy<#)9Y@w}$Zq*Z4xQu-9=m7@t_qp7KiLqGbG!Fy2DO1BJ0FX2#ZwH{rf<9tfPD z5p!d#?l9gUj9(#REQp?QpW`r|sEpU!FfO{0J>`|g#mM+?VH``w1B9_E4vYs`FK)hr z6`LDlb%!xdanP>gmSl_t(Kl`g<4LaZ#nA8DbgtvC_pqnD(zrMo-xbDN$@o2Ctcsbj z_2SJ(S+Th>R(BZV6bH@tRWinc=o!DW8^)8B@eUi;arWcvDX%mxLB@B4@isDkR~W0} zz<8kb;?}>hVsm4x?l8s~3Yu{%GRA`F8&`z!XRh(3x;BhU{l=d1O5>7b{FgA^PR9L( zu_|W9){CoNVa4XgSlwZaGZZxA*T@(PqG#OOIj?PsGCpj>c-bBHlvf&;BIDb_cn2Bx z6UM4IFdksNc>g0-Y;KIz9mY6AK{IYm##j)2<6Kb2eVZ*q>BeoPuOBgrsp9GQKH{ zcad=)VXTS+V^tg&_p@I7VF^}jZj99(#yCSkGww*nSP*^V zJ}~~=HNKwA#_RFPQct{hD^JE(h4Fqeep48$VrFc;__Hdk*xVSaJB)FLf@a)_jIkhk z#&2AQ@f>A5$%gTgO6)1GypAi7@fBfwfQ;V|#;Q0l?rXhx&r7V>+!(7njB$p7X55*K zu^{@!onbuJHU1+*SmPXct!STy-3dwKie!9Q7#}3#p2AoaGh^$;owKlFb7QRTFvb}Q znsFC0#)9Y>_xu&c^OSMu_iZ}Hw=%OkA!%HRj4uh}LuA}T7^~vIxR3SX`*~ThxiMCE z7~>2D&A2NWV?p$dUxx8~*Z4*O8`tsh66`6jG_Fj>7lrX*GVU&nRWUQRUOciqD>gUA z>JDR^p`aOeBV#Oxo^g-;FkYaHSK2V{TaG>DmBv-b_<}G#LdM;Mu__LX-?3i&Mh#YM zZj99(#yCSkGwx2tSP*^V7h$~6HU6`d4dXt|*;8I=T$PN^3*#TixT`Q$#mv}x@t}6B z*xVSaJB)FLf@a)v8gS>?yA_u13b^gz-@_?jnp;abVor zdU4Y3tk~Qbt2>NwhJt3?lZ>$-`o^VUyvQ}a8Tx&jj`8eXY$=q+)yepGVSJ2?I}2k~ z%#5uU?|P3Fn;TR(BZV3`7^`AtY`yq}_gS&IF;;gN&lASI$QTQvXWX?hjF-B`xAWLAJ~Eu$2}$D@ z$@n*6e3Fbi2xCd|DX)M8@reu__LX-?Uyl_T+!Mcf;xqW1OL&8NWluSP*?<=QN1ruJN5( zHjFns`Mbc>A>*Hg@y}%3Rv4>dW^BFqz<>KLFj(DTj58E8<341J1<^C^Gz-Qnl<~2! z#<}oXQ4X&>Pq=rhOU6G5!lOVZ2HipSE!wKibaTp(l;&lkq8G{3{v1CX7{aVBFJsalM1A*xVSaJFa7#p`aP# zZ!|cM9t)yxoCLVX58Dl~8jo*av*UC8b`zxI5xNdj0VoBr1WPD5*|4zoQ2xC>u zjI9?>?8A!9jj_7J7-uMG#skS13!-QI`au}u-o-gj=-$k**KuwbZ!N~|grsp3GCnGd z&yjHpVXTS+<8IcAkG;T(&5g0T!x(2MXvTxc7z?6r?0om5b*}NhIcyl`tj6wyq;XR+ z{y`X@C*$VASQRs4>&3O}v0`&$tnM(z848;5`(%s-(KBur3*+_5IP_=7oa=aLA9g1s zjbA3?Bf|Is88;KgsyHz2YQ6Z@U{-8yjMW{+I72}*9!$nq5PjpKFy7!A-!E(9I%%1LH2%i`Vdz70r#Yy2BV}C}_qXkTDiS-#90XH@U|D z3;jILF>W)5y+cnLw;7Hxb6Fm>F9y{$eRBHaEuV4r835pcxM(V=RcCahs_y z-mHv6KhJZFTd!d6(38fmknsUwe1(h~3u9Fr7Tw^pVHaEuV4r835 zpcxM%V=RciaTJWVxW*4dKbLllOH5=>d8KhHGTtkUuaj{DVXTUovGwBDX0c*(W328l z#u*Bl@o+N6g6J8)HW0?K%J{sE>v-}a_LNr|zedJ;gz+C_TwfTg;=s70_2QAMSh2Y= zR(BZV3>!*@uMC#jEApfPkE(rYcl>`7~de{dcs&02gV(&7mxam z6`LDlb%!y|P|%D=k}(!U-?$r$w<+U0HjJz6Vo!OcaT_w;EsXypL~6g1;c$QTQvXWa4-jCU&I(Kd{yRY?(X-b~>96eq{bi9{+#;)+IP zu63YHO~*MBiHX#Rjf^aS4f|2iP8%O9j*awkev|0bM^?s*7cc5eB$7BfCORh4YToJS zXy@O+FCA;Qmr1%Kf#B{GX#=OP4O)WB*)U+!fWw-xcQJ zKj{4Yf4+mv>vV0co=afR%1IO3;`N*DGDaf;jTVLPY%Z((~f-Y$&)BI8=ZSQRs4>%~KkvSM>%?Ab8J z=>(eb7&6BG=^4MW6~_2FlJQg<#>swTJEt`6K*rmI@f|XLQ5dV@z_^|D;&xY9vAHq! zY#4tij6Wq~?4Q1IDHwn68b{}`VVw6e+c~9iM>5_jjPH_hO<}BxnX&ca3b$FYxiR)^ z7!MW3W62o%r)S(^1&sG7gUA zo(*H1PN2P3j3Z<0pT2QE81HqBjQNdhw^p zSh2Y=_G}mr5ys=m82hJZ+v#egWB>Gxv%q-2YaBoHlQQQz-j{)$dn1jzlJU2~_+K)vDvVVz zGqzs5D;Fy^H^x0GjBz@FW;~IMv448T&7AkX9Z<%hpOoc;ajCOx=ak0X$au3bzE8$g zgt00Pj9XhT&T@?vn;T=#hA~bj(2OUMG4@a2I0=joy2c4YzkAv-uJ;$)Ii+!TGTtPN z|3}7^g|RAT#@36=J!Hk^#@MrAjME7;&1r>{il1kSTe@x1e!7a=8boqV*m7vn?8W?Vb?fe=qF{4 zajVqqPDmQ}B;yUj_#qir6vnDJFm7eNxL#&fYR-;V^z$ItrySbXA7AdZzE%zPM}@KQ^^?nr)S*cDvW<{ zjT3bUd++8LuX~0)qn5^RlJPoWj8O`&73GDoDh`ZawO%}dpDko=j6ECIF-|AYjHi(? z_D|oqBaDwKKzs+8Z**fkYv(1gb|)l_-y-9$g>e)azaWfNabVoidhzTGtk~Qb zdp3;w3ga1Mj0Mp*ZUW=u%J`lQ<1*RUoscwsn~c{A<7hH|UKp!lW^BEz{zZj413 z#yFioyN+j)F&0G6xY1r1pKy&653ylF9y{^%uE zY;KH27{)lAKr^0A##j(NDd`cOQvtj&l6ZVW+8uuaNRl+y{8J7{psyHxiVZFG? zYpmGZ7>h8BaXNu!{5ct8LG+D_!uUtmIB5nO#wlB~rBE98CF7OCI3XFA7RIWW8Cx%| z+=UgJ8)FfMF-|AYjOUOs7DUgu!BQCiq>MvBsj0Mp*cD|S1&#rN@0%5P?0x<6I5_`%kjr)`Fa$y`p z#wCTZDrUyki^nu!#pcFXgkg-+2{dCokjGwu1<^CEKMBUCm2v3P=^W!LP1#dkY5Xo3 zeh8BaXNu!ypW8sAo|8pF#gRoPEpy0ar6Fc zDU`+o$#|(SPDaK>g|RAT#@3754`s#X##n@5jME7;<1fe<3!-OSw?B-}DC6&K7{C1C z6SvJlWV}QeCnw_~!dMjt#!amkHyXo=&5f}L!x*O%XvT}k7z?6jT<0$spLLB>*0o_= z^Rp*zo9~nHVqu(ujGq<8syHxiV!e3499C>@j71p6IGsQu5qeX zVT}vo-mT*sY$=q+L&*3GVVsJL3khRY92hsYUOb{dD>gUAA`D}kPM{etC1WgzzHuuU zpI63bY#6s)#Fj#7`~ev+6vnB^_!(iWikY$X;&rQ7vAHo8VHo3d0?qhKGRA`F8Naj} z#ur@U)S)+e=Qnk|LWcqkb!5XNc9xS%jr#es1n>&0ESuwrv#EW$9x=>(ebGBU=3 z=o?ps@kM1EdZTxYH|%6fp)~%GjOPpEv}9aB7^`AtY`u8@Ay#Z|j71p69fa{$WQ+yT zGp^-)FTG2yahlK@y<^daGrBE6VBjdTk_$e~ZCyZ4wGqzrQ<_}hEZj413#yFio zd#zYO##j(N;};jf_=++Pz0o_yv!dCZkTf1n#&d-6(`1}i7^~vIxPkTJ1<6>kxiJ=D z7~^yT&3GjlV?p$dv%&bPYn(3hM*j?qJMLvmp)?*r#-9u0^kkez7^`AtY`u6P?!qwd zxt|g;H^w3i+h6&Yhe^o(mxhVeCJJSXhEn`7MPXSNhd3X{u?WK$rxR$`@oF;0g6JD3gYk9O_^Hqvy<>d-B3lZj@yBF5OBiP)<6Od6 z6*FV&#gSXA*xVS4FpP0Jfo8mhjIkhk#x+L3_zz{g%*J)x@-Ma&O5;&vJX08FBIBIG zSQQ7x^{f|v`H&Tx8)FfMF-|AYjMtJe7DUgu`Xd-Y>A<8%Ve_!~0Dg6J7ny9wi)u5tR%8@+QKci^93 zk;Y@lc$zTIO2*lQu__LX>sT-Do9#b6m&PKD>$s&bUPs1Q5PjqBFutXXci6a&Qx#yJ zV3Ee3lJQhwoQ;gL3S(8wjI9^nF3yV0uVXC2FvjTw+I761jIkhk##MiZ@om>QL+FjZ z5U%5957<&DjmMJl6k(j5jI#)1RU8=Cwq9I4;eWb!!y*i0oKBz_Zy;kVh`#YFF#by! zhu-KN>y#pcFXgkg-& z_iM)AkuerT&$!ZJ7~gY^Gl$;jo$L6UH`r1rjVF`wcwwBEjGq?9syHxy(Ry*e{;b&C z7>h8B@%etucncY0LG+Dt!}wp!bgVSHa1j}H4<;TT`4!=CcW>v#$oj}^xG$vB-bR>gsF zP3y&pnz3SYV=Tfj#^?JrF9yp52obn;T;hhA}?huNiM6V=RcCafOjEexQs)zmMLzj&t^5PkE*BG%_9|j0=)+ z8ey!81LGRji<1v##pcFXgkg-&_iM)6$ruZwXIwrG#t&WNY@yF=a*Q_&WJ{qmo=(Q2 zh4C|FoLU&G;=s7N_2MhTS+Th>7GW6U^ZlCf4l>4q=o`NW<44MPv5nV?N+Z}(D2->3 z@h8H#5E-Wu#;TYZTQ43oo)w!LV-bciKHsky?<8X^h@Nq|TQH7ujk6cCVLW&WTMDJ| zOfnuNj0=--N@1*u1LJDei^tAo#pcFXgkg-&_iM(x$QTQvZ`>u49+MY-#7~<&^hWj71p6_3CF5kmSQRs4>%{}Nv0`&$EW$9x=leC|J!Fgp(KCL2 zCye8{#yMNqFdiMtmO^Pfhm3~{<6>l-R2Zw`z_^O_;uU*YvAHo8VHo4{{hBe}!-LP~ zVL|kb%fmRnG7i0MI(_( zBV#Oxo^jbVFizka=jvkRI=;b{LTNmYj6V{_CCE6jFjmEZab@epKi*@-=EhirVO&EP z?0} zd#yM~##j)2;|ws4agFmt!WtLB>v8lQwiHU^g=GAJFfL8T35BsLX2#Zw(>`Lw=Ehir zVT{lBYsQDj7z?6jT;>xPCsxLxw@t^mK@__alEz<<@epBLhKv&kV^tg&SF~OnlY|wU z8)FfMF+Sg~86PHNEQr2wLKr7;jq|3maUG9J%-xtPZ$vB=cR>gsF1?$D> z3b0~xV=Tfj#^?Jr;~&Tv3!-OS>JE&PxyJc&*f6eGh}{WE<0WJ~NEkm)#?iu96$i%U ztrvGH&5F&9u?WK$pYPXX2*Vhk@7IivkuerT&$#487^iTJ^B1;Zysk2P$}5e(B;x_XxEvWrgt00P zjLTUszFwOZn_tIRgkg-&_iM(-$ruZwZ`=;XDV6ccu*OAkU$G+gPR2s9Yu^ZlCf2{Oil=oyzd1>;n%ae=ZnjK6-0J>`|gUy<>< z!ngt%KN7~OI52*}dhs=kV)!dQ{S@E3X;LIo+4?xMjL-LL#wW=b z3!-n_1jebA@n##wt%|d!ywZ3%8TS{)70LLaFjmFP*n08Ya;(_=I>sUlV|>0}Gd@Me zSP(tq;=5p+#x*Wj%ZBl`YV0YmG+sf*{e*EPGJYV8RdHbay!GNN4Op?cF&1GM$p6Y2meoLX}pGvdkf=gWPDE;tKz`; zIqStk@ZTZ7*xVS4FpTl}e$Dt7GRA`F8|Q>^dS!gshVix<>?yA_UQ5Pr3*+i!{EskJ z#mv}x@yQ0P*xVS4FpTl}e$Dt-GRA`F85fxf;|#8G;a)b3x71@xp)~%QjNcN*HOTmH zVXTS+<1*HZV_L9cb7L&RFvjQmHRIpN7z?6roEF9zm2v3z(L1jd>t1I|p)~%6jC%>= znq+)e7^`AtY`yqm4_0h$j71p6_8+J=jtxjn|R! zo5J`-GQJ~>RdHZk+In%ezO2~X7>h8B@%etu_$(P?LG+EIV4T@CE)x2E^v-qMU?f`# zrSW<)enS}7BICb=u_|W9){6&BV8!OfScGAW&-ZJ_zmqW*M9;Wze;8*`#-X1zImVr4 zu%%EMZy@8I!uTaJzAcPZabR4^dhzEAS+Th>7GW6U^ZlCfIWoqA=ouIK6UJFxgMHz9EcNF*CMad}JvrHaEs13}bx0Uo*Z$ z##j(NF9ye*Oq6HaEs1 z3}bx0Uo*Z!##j(N;{qFCoZB@nQQgLMeBlSS6iVY*GVUad8iHrvVg@$)NU zBXwIgA>$U08OKISIloDC>Lb_U#fukxCK5>;9TOcB$n3w538nC2)*?*vGa?X}pt++X>^B$@ro$R>gsF5$nb2Pq1Qh zV{Fne#t8$O@eMM@hUpupgK+_6eBQ=?lNS8Uwn}Ndi;UX}<7Q-hK^UuIW^BFqzy(%p zZj4PD#yDX>Gyao|v0-|~c|U=1LD#r+4;#j{uClFC8t*3KHo~|$8J`!%syHxy)@t$p E0q`ViQ2+n{ literal 0 HcmV?d00001 diff --git a/testing/btest/core/tunnels/gre-in-gre.test b/testing/btest/core/tunnels/gre-in-gre.test new file mode 100644 index 0000000000..ce85f54dbb --- /dev/null +++ b/testing/btest/core/tunnels/gre-in-gre.test @@ -0,0 +1,3 @@ +# @TEST-EXEC: bro -r $TRACES/tunnels/gre-within-gre.pcap +# @TEST-EXEC: btest-diff conn.log +# @TEST-EXEC: btest-diff tunnel.log diff --git a/testing/btest/core/tunnels/gre.test b/testing/btest/core/tunnels/gre.test new file mode 100644 index 0000000000..0ce9a0c8b8 --- /dev/null +++ b/testing/btest/core/tunnels/gre.test @@ -0,0 +1,5 @@ +# @TEST-EXEC: bro -r $TRACES/tunnels/gre-sample.pcap +# @TEST-EXEC: btest-diff conn.log +# @TEST-EXEC: btest-diff tunnel.log +# @TEST-EXEC: btest-diff dns.log +# @TEST-EXEC: btest-diff ssh.log From 4901032660167a156261c6b0d5023c6fe19680a1 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Thu, 16 Jan 2014 16:40:23 -0600 Subject: [PATCH 2/2] Simplify FragReassembler memory management. --- src/Sessions.cc | 26 +++----------------------- src/Sessions.h | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/src/Sessions.cc b/src/Sessions.cc index cc5e48a9b5..f4131d6a10 100644 --- a/src/Sessions.cc +++ b/src/Sessions.cc @@ -471,6 +471,8 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, } } + FragReassemblerTracker frt(this, f); + len -= ip_hdr_len; // remove IP header caplen -= ip_hdr_len; @@ -485,7 +487,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, vl->append(ip_hdr->BuildPktHdrVal()); mgr.QueueEvent(esp_packet, vl); } - Remove(f); + // Can't do more since upper-layer payloads are going to be encrypted. return; } @@ -500,7 +502,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, if ( ! ignore_checksums && mobility_header_checksum(ip_hdr) != 0xffff ) { Weird("bad_MH_checksum", hdr, pkt, encapsulation); - Remove(f); return; } @@ -514,7 +515,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, if ( ip_hdr->NextProto() != IPPROTO_NONE ) Weird("mobility_piggyback", hdr, pkt, encapsulation); - Remove(f); return; } #endif @@ -522,10 +522,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, int proto = ip_hdr->NextProto(); if ( CheckHeaderTrunc(proto, len, caplen, hdr, pkt, encapsulation) ) - { - Remove(f); return; - } const u_char* data = ip_hdr->Payload(); @@ -592,7 +589,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, if ( ! BifConst::Tunnel::enable_gre ) { Weird("GRE_tunnel", ip_hdr, encapsulation); - Remove(f); return; } @@ -604,7 +600,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, { Weird(fmt("unknown_gre_version_%d", gre_version), ip_hdr, encapsulation); - Remove(f); return; } @@ -615,7 +610,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, // Not IPv4/IPv6 payload. Weird(fmt("unknown_gre_protocol_%"PRIu16, proto_typ), ip_hdr, encapsulation); - Remove(f); return; } @@ -627,7 +621,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, { // Enhanced GRE payload must be PPP. Weird("egre_protocol_type", ip_hdr, encapsulation); - Remove(f); return; } } @@ -638,7 +631,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, // specified by RFC 1701. It could be parsed here, but easiest // to just skip for now. Weird("gre_routing", ip_hdr, encapsulation); - Remove(f); return; } @@ -646,7 +638,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, { // Expect last 4 bits of flags are reserved, undefined. Weird("unknown_gre_flags", ip_hdr, encapsulation); - Remove(f); return; } @@ -656,7 +647,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, if ( len < gre_len + ppp_len || caplen < gre_len + ppp_len ) { Weird("truncated_GRE", ip_hdr, encapsulation); - Remove(f); return; } @@ -667,7 +657,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, if ( ppp_proto != 0x0021 && ppp_proto != 0x0057 ) { Weird("non_ip_packet_in_egre", ip_hdr, encapsulation); - Remove(f); return; } @@ -688,7 +677,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, if ( ! BifConst::Tunnel::enable_ip ) { Weird("IP_tunnel", ip_hdr, encapsulation); - Remove(f); return; } @@ -696,7 +684,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, encapsulation->Depth() >= BifConst::Tunnel::max_depth ) { Weird("exceeded_tunnel_max_depth", ip_hdr, encapsulation); - Remove(f); return; } @@ -713,7 +700,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, if ( result != 0 ) { delete inner; - Remove(f); return; } @@ -740,7 +726,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, DoNextInnerPacket(t, hdr, inner, encapsulation, ip_tunnels[tunnel_idx].first); - Remove(f); return; } @@ -753,13 +738,11 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, encapsulation->LastType() == BifEnum::Tunnel::TEREDO ) ) Weird("ipv6_no_next", hdr, pkt); - Remove(f); return; } default: Weird(fmt("unknown_protocol_%d", proto), hdr, pkt, encapsulation); - Remove(f); return; } @@ -785,7 +768,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, if ( consistent < 0 ) { delete h; - Remove(f); return; } @@ -809,7 +791,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, if ( ! conn ) { delete h; - Remove(f); return; } @@ -841,7 +822,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, { // Above we already recorded the fragment in its entirety. f->DeleteTimer(); - Remove(f); } else if ( record_packet ) diff --git a/src/Sessions.h b/src/Sessions.h index 1788541f45..e2dec3b1aa 100644 --- a/src/Sessions.h +++ b/src/Sessions.h @@ -286,6 +286,21 @@ protected: NetSessions::IPPair tunnel_idx; }; + +class FragReassemblerTracker { +public: + FragReassemblerTracker(NetSessions* s, FragReassembler* f) + : net_sessions(s), frag_reassembler(f) + { } + + ~FragReassemblerTracker() + { net_sessions->Remove(frag_reassembler); } + +private: + NetSessions* net_sessions; + FragReassembler* frag_reassembler; +}; + // Manager for the currently active sessions. extern NetSessions* sessions;