-
Notifications
You must be signed in to change notification settings - Fork 1.6k
decoder/l2tp: initial implementation of decoder #14023
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your contribution!
Some initial comments inline. I'll also let this run CI and our QA, I suspect there will be some more issues as at least the formatting seems off in a few places (run clang-format on the diff: git clang-format HEAD~
) and I suspect the debug build is broken.
src/decode-l2tp.c
Outdated
case ETHERNET_TYPE_VNTAG: | ||
eth_found = true; | ||
break; | ||
default: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add a comment explaining why we consume 4 bytes here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this code seems like dead code? If eth_found isn't set we should hit the !eth_found
exit path directly after?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's dead because it is i<4 && !eth_found;
?
Comment added.
NOTE: This PR may contain new authors. |
Additionally we would love to see some pcap based Suricata Verify tests. |
CI: the Cargo audit test failure is unrelated and expected. |
8b1d86e
to
5149224
Compare
Happy to add some this week from some hardware we have on hand |
NOTE: This PR may contain new authors. |
…coder.properties.event.properties
WARNING:
Pipeline = 27975 |
NOTE: This PR may contain new authors. |
QA result shows an increase of invalid packets. This suggests the logic to detect the protocol should be tighter. At least that is what VXLAN has shown us previously. |
Cool, I'll take a look and see if I can tighten it up later tonight/tomorrow |
Think we're almost there. There is a compile warning left:
Plus a few schema things missing. Then combined with a SV PR we'd like to see a new (rebased) PR. |
- Add a strict option similar to VXLAN checking reserved bits and only return TM_ECODE_FAILED if it is set for invalid L2TP headers - Tighten to only IPv4, IPv6, VLAN, or ARP encapsulated packets (similar to VXLAN) - No longer return TM_ECODE_FAILED if we cannot find an encapsulated packet (similar to VXLAN)
I've fixed the compile warning by changing to
Can you please run the QA over this and see if the logic change is better? If it's acceptable then I'll then create a SV PR tomorrow and rebase this PR into a new PR. |
eth_found = true; /* breaks the loop */ | ||
break; | ||
default: /* consume 4 bytes to detect all combinations of cookie/sublayer types */ | ||
len -= sizeof(uint32_t); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RFC https://datatracker.ietf.org/doc/html/rfc3931#section-4.1 says that Cookie could be at most 64 bits. Is there any chance this might underflow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but the extra 32-bits is to detect the optional L2-Specific Sublayer, which can exist between the Cookie and the Tunnel itself: https://datatracker.ietf.org/doc/html/rfc3931#section-3.2.2
The suggested L2-Specific Sublayer is 32-bits in the RFC: https://datatracker.ietf.org/doc/html/rfc3931#section-4.6
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually re: underflow we check for +14 bytes (Ethernet Header) on each iteration of the loop, so it would not underflow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see that the cookie should be a multiple of 4 bytes in the RFC. It just says variable length.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct, but the only implementations I've run into the wild with the cookie are multiples of 4 bytes. Take for example the iproute(2)
documentation on L2TPv3:
cookie HEXSTR
sets an optional cookie value to be assigned to the session. This is a 4 or 8 byte value, specified as 8 or 16 hex digits, e.g. 014d3636deadbeef. The value must match the peer_cookie value set at the peer. The cookie value is carried in L2TP data packets and is checked for expected value at the peer. Default is to use no cookie.
Similar with the L2-Specific Sublayer, there's no custom option only the default (from the RFC) on or off:
l2spec_type L2SPECTYPE
set the layer2specific header type of the session.
Valid values are: none, default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mikrotik's documentation [1] is similar for Cookies (0, 4, 8 byte only) and the SubLayer (on (4 byte) / off (0 byte))
peer-cookie ( string; Default: disabled) | Sets optional peer cookie. To enable cookie enter remote cookie value (8 or 16 character hex string value expected) to disable leave empty.
send-cookie ( string; Default: disabled) | Sets optional cookie. To enable cookie enter remote cookie value (8 or 16 character hex string value expected) to disable leave empty.
use-l2-specific-sublayer ( yes | no; Default: no) |
[1] https://help.mikrotik.com/docs/spaces/ROS/pages/2031631/L2TP#L2TP-L2TPEther
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cisco as well [1]
The size of the cookie field can be 4 or 8 bytes. If you do not enter this command, no cookie value is included in the header of L2TP packets.
#define L2TP_DEFAULT_PORT_S "1701" | ||
|
||
/* Although L2TPv3 can do non-IP (like ATM), assume that there's a trailing ethernet header */ | ||
#define L2TP_MIN_HEADER_LEN sizeof(L2TPoverUDPDataHdr) + sizeof(EthernetHdr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this trailing Ethernet header always in full i.e. 14 bytes ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes from what I've observed.
I've seen one edge case where we had some fragmentation due to mis-configuration (9000 MTU host forwarding to a 1500 MTU host) and because the L2TPv3 payload was the inner-most encapsulation it split the ethernet header across two packets. We set tunnel depth to non-default, so I would not expect to see this in the wild.
} | ||
/* check the protocol type */ | ||
EthernetHdr *ethh = (EthernetHdr *)(pkt); | ||
uint16_t proto = SCNtohs(ethh->eth_type); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here we take bytes 12/13 as eth header and check if it is a known type, but what if the cookie is still present and we just interpret some bytes from the hwaddresses as eth type? Then we could interpret address bytes as eth type?
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #14023 +/- ##
==========================================
+ Coverage 83.87% 84.44% +0.57%
==========================================
Files 1011 1013 +2
Lines 275671 272534 -3137
==========================================
- Hits 231207 230154 -1053
+ Misses 44464 42380 -2084
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
Btw there is a public pcap here https://wiki.wireshark.org/uploads/__moin_import__/attachments/SampleCaptures/nb6-http.pcap |
Issue: 7986
Make sure these boxes are checked accordingly before submitting your Pull Request -- thank you.
Contribution style:
https://docs.suricata.io/en/latest/devguide/contributing/contribution-process.html
Our Contribution agreements:
https://suricata.io/about/contribution-agreement/ (note: this is only required once)
Changes (if applicable):
(including schema descriptions)
https://redmine.openinfosecfoundation.org/projects/suricata/issues
Link to ticket: https://redmine.openinfosecfoundation.org/issues/7986
Describe changes:
Provide values to any of the below to override the defaults.
link to the pull request in the respective
_BRANCH
variable.SV_REPO=
SV_BRANCH=
SU_REPO=
SU_BRANCH=