suricata
decode-pppoe.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2013 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \ingroup decode
20  *
21  * @{
22  */
23 
24 
25 /**
26  * \file
27  *
28  * \author James Riden <jamesr@europe.com>
29  *
30  * PPPOE Decoder
31  */
32 
33 #include "suricata-common.h"
34 
35 #include "packet-queue.h"
36 
37 #include "decode.h"
38 #include "decode-ppp.h"
39 #include "decode-pppoe.h"
40 #include "decode-events.h"
41 
42 #include "flow.h"
43 
44 #include "util-unittest.h"
45 #include "util-debug.h"
46 
47 /**
48  * \brief Main decoding function for PPPOE Discovery packets
49  */
50 int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint32_t len, PacketQueue *pq)
51 {
52  StatsIncr(tv, dtv->counter_pppoe);
53 
56  return TM_ECODE_FAILED;
57  }
58 
59  p->pppoedh = (PPPOEDiscoveryHdr *)pkt;
60  if (p->pppoedh == NULL)
61  return TM_ECODE_FAILED;
62 
63  /* parse the PPPOE code */
64  switch (p->pppoedh->pppoe_code)
65  {
66  case PPPOE_CODE_PADI:
67  break;
68  case PPPOE_CODE_PADO:
69  break;
70  case PPPOE_CODE_PADR:
71  break;
72  case PPPOE_CODE_PADS:
73  break;
74  case PPPOE_CODE_PADT:
75  break;
76  default:
77  SCLogDebug("unknown PPPOE code: 0x%0"PRIX8"", p->pppoedh->pppoe_code);
79  return TM_ECODE_OK;
80  }
81 
82  /* parse any tags we have in the packet */
83 
84  uint32_t tag_length = 0;
85  PPPOEDiscoveryTag* pppoedt = (PPPOEDiscoveryTag*) (p->pppoedh + PPPOE_DISCOVERY_HEADER_MIN_LEN);
86 
87  uint32_t pppoe_length = SCNtohs(p->pppoedh->pppoe_length);
88  uint32_t packet_length = len - PPPOE_DISCOVERY_HEADER_MIN_LEN ;
89 
90  SCLogDebug("pppoe_length %"PRIu32", packet_length %"PRIu32"",
91  pppoe_length, packet_length);
92 
93  if (pppoe_length > packet_length) {
94  SCLogDebug("malformed PPPOE tags");
96  return TM_ECODE_OK;
97  }
98 
99  while (pppoedt < (PPPOEDiscoveryTag*) (pkt + (len - sizeof(PPPOEDiscoveryTag))) && pppoe_length >=4 && packet_length >=4)
100  {
101 #ifdef DEBUG
102  uint16_t tag_type = SCNtohs(pppoedt->pppoe_tag_type);
103 #endif
104  tag_length = SCNtohs(pppoedt->pppoe_tag_length);
105 
106  SCLogDebug ("PPPoE Tag type %x, length %"PRIu32, tag_type, tag_length);
107 
108  if (pppoe_length >= (4 + tag_length)) {
109  pppoe_length -= (4 + tag_length);
110  } else {
111  pppoe_length = 0; // don't want an underflow
112  }
113 
114  if (packet_length >= 4 + tag_length) {
115  packet_length -= (4 + tag_length);
116  } else {
117  packet_length = 0; // don't want an underflow
118  }
119 
120  pppoedt = pppoedt + (4 + tag_length);
121  }
122 
123  return TM_ECODE_OK;
124 }
125 
126 /**
127  * \brief Main decoding function for PPPOE Session packets
128  */
129 int DecodePPPOESession(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint32_t len, PacketQueue *pq)
130 {
131  StatsIncr(tv, dtv->counter_pppoe);
132 
133  if (len < PPPOE_SESSION_HEADER_LEN) {
135  return TM_ECODE_FAILED;
136  }
137 
138  p->pppoesh = (PPPOESessionHdr *)pkt;
139  if (p->pppoesh == NULL)
140  return TM_ECODE_FAILED;
141 
142  SCLogDebug("PPPOE VERSION %" PRIu32 " TYPE %" PRIu32 " CODE %" PRIu32 " SESSIONID %" PRIu32 " LENGTH %" PRIu32 "",
144 
145  /* can't use DecodePPP() here because we only get a single 2-byte word to indicate protocol instead of the full PPP header */
146 
147  if (SCNtohs(p->pppoesh->pppoe_length) > 0) {
148  /* decode contained PPP packet */
149 
150  switch (SCNtohs(p->pppoesh->protocol))
151  {
152  case PPP_VJ_COMP:
153  case PPP_IPX:
154  case PPP_OSI:
155  case PPP_NS:
156  case PPP_DECNET:
157  case PPP_APPLE:
158  case PPP_BRPDU:
159  case PPP_STII:
160  case PPP_VINES:
161  case PPP_HELLO:
162  case PPP_LUXCOM:
163  case PPP_SNS:
164  case PPP_MPLS_UCAST:
165  case PPP_MPLS_MCAST:
166  case PPP_IPCP:
167  case PPP_OSICP:
168  case PPP_NSCP:
169  case PPP_DECNETCP:
170  case PPP_APPLECP:
171  case PPP_IPXCP:
172  case PPP_STIICP:
173  case PPP_VINESCP:
174  case PPP_IPV6CP:
175  case PPP_MPLSCP:
176  case PPP_LCP:
177  case PPP_PAP:
178  case PPP_LQM:
179  case PPP_CHAP:
181  break;
182 
183  case PPP_VJ_UCOMP:
184 
187  return TM_ECODE_OK;
188  }
189  if (unlikely(len > PPPOE_SESSION_HEADER_LEN + USHRT_MAX)) {
190  return TM_ECODE_FAILED;
191  }
192 
193  if(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + PPPOE_SESSION_HEADER_LEN)) == 4) {
194  DecodeIPV4(tv, dtv, p, pkt + PPPOE_SESSION_HEADER_LEN, len - PPPOE_SESSION_HEADER_LEN, pq );
195  }
196  break;
197 
198  case PPP_IP:
201  return TM_ECODE_OK;
202  }
203  if (unlikely(len > PPPOE_SESSION_HEADER_LEN + USHRT_MAX)) {
204  return TM_ECODE_FAILED;
205  }
206 
207  DecodeIPV4(tv, dtv, p, pkt + PPPOE_SESSION_HEADER_LEN, len - PPPOE_SESSION_HEADER_LEN, pq );
208  break;
209 
210  /* PPP IPv6 was not tested */
211  case PPP_IPV6:
214  return TM_ECODE_OK;
215  }
216  if (unlikely(len > PPPOE_SESSION_HEADER_LEN + USHRT_MAX)) {
217  return TM_ECODE_FAILED;
218  }
219 
220  DecodeIPV6(tv, dtv, p, pkt + PPPOE_SESSION_HEADER_LEN, len - PPPOE_SESSION_HEADER_LEN, pq );
221  break;
222 
223  default:
224  SCLogDebug("unknown PPP protocol: %" PRIx32 "",SCNtohs(p->ppph->protocol));
226  return TM_ECODE_OK;
227  }
228  }
229  return TM_ECODE_OK;
230 }
231 
232 #ifdef UNITTESTS
233 /** DecodePPPOEtest01
234  * \brief Decode malformed PPPOE packet (too short)
235  * \retval 1 Expected test value
236  */
237 static int DecodePPPOEtest01 (void)
238 {
239 
240  uint8_t raw_pppoe[] = { 0x11, 0x00, 0x00, 0x00, 0x00 };
241  Packet *p = PacketGetFromAlloc();
242  if (unlikely(p == NULL))
243  return 0;
244  ThreadVars tv;
245  DecodeThreadVars dtv;
246 
247  memset(&tv, 0, sizeof(ThreadVars));
248  memset(&dtv, 0, sizeof(DecodeThreadVars));
249 
250  DecodePPPOESession(&tv, &dtv, p, raw_pppoe, sizeof(raw_pppoe), NULL);
251 
253  SCFree(p);
254  return 1;
255  }
256 
257  SCFree(p);
258  return 0;
259 }
260 
261 /** DecodePPPOEtest02
262  * \brief Valid PPPOE packet - check the invalid ICMP type encapsulated is flagged
263  * \retval 0 Expected test value
264  */
265 static int DecodePPPOEtest02 (void)
266 {
267 
268  uint8_t raw_pppoe[] = {
269  0x11, 0x00, 0x00, 0x01, 0x00, 0x40, 0x00, 0x21,
270  0x45, 0x00, 0x00, 0x3c, 0x05, 0x5c, 0x00, 0x00,
271  0x20, 0x01, 0xff, 0x30, 0xc0, 0xa8, 0x0a, 0x7f,
272  0xc0, 0xa8, 0x0a, 0x65, 0xab, 0xcd, 0x16, 0x5e,
273  0x02, 0x00, 0x37, 0x00, 0x41, 0x42, 0x43, 0x44,
274  0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
275  0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54,
276  0x55, 0x56, 0x57, 0x41, 0x42, 0x43, 0x44, 0x45,
277  0x46, 0x47, 0x48, 0x49 };
278 
279  Packet *p = PacketGetFromAlloc();
280  if (unlikely(p == NULL))
281  return 0;
282  ThreadVars tv;
283  DecodeThreadVars dtv;
284  int ret = 0;
285 
286  memset(&tv, 0, sizeof(ThreadVars));
287  memset(&dtv, 0, sizeof(DecodeThreadVars));
288 
290 
291  DecodePPPOESession(&tv, &dtv, p, raw_pppoe, sizeof(raw_pppoe), NULL);
292 
294  goto end;
295  }
296 
297  // and we insist that the invalid ICMP encapsulated (type 0xab, code 0xcd) is flagged
298 
300  goto end;
301  }
302 
303  ret = 1;
304 end:
305  FlowShutdown();
306  SCFree(p);
307  return ret;
308 }
309 
310 
311 /** DecodePPPOEtest03
312  * \brief Valid example PADO packet PPPOE packet taken from RFC2516
313  * \retval 0 Expected test value
314  */
315 static int DecodePPPOEtest03 (void)
316 {
317 
318  /* example PADO packet taken from RFC2516 */
319  uint8_t raw_pppoe[] = {
320  0x11, 0x07, 0x00, 0x00, 0x00, 0x20, 0x01, 0x01,
321  0x00, 0x00, 0x01, 0x02, 0x00, 0x18, 0x47, 0x6f,
322  0x20, 0x52, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b,
323  0x20, 0x2d, 0x20, 0x65, 0x73, 0x68, 0x73, 0x68,
324  0x65, 0x73, 0x68, 0x6f, 0x6f, 0x74
325  };
326 
327  Packet *p = PacketGetFromAlloc();
328  if (unlikely(p == NULL))
329  return 0;
330  ThreadVars tv;
331  DecodeThreadVars dtv;
332 
333  memset(&tv, 0, sizeof(ThreadVars));
334  memset(&dtv, 0, sizeof(DecodeThreadVars));
335 
336  DecodePPPOEDiscovery(&tv, &dtv, p, raw_pppoe, sizeof(raw_pppoe), NULL);
337  if (p->pppoedh == NULL) {
338  SCFree(p);
339  return 0;
340  }
341 
342  SCFree(p);
343  return 1;
344 }
345 
346 /** DecodePPPOEtest04
347  * \brief Valid example PPPOE packet taken from RFC2516 - but with wrong PPPOE code
348  * \retval 1 Expected test value
349  */
350 static int DecodePPPOEtest04 (void)
351 {
352 
353  /* example PADI packet taken from RFC2516, but with wrong code */
354  uint8_t raw_pppoe[] = {
355  0x11, 0xbb, 0x00, 0x00, 0x00, 0x04, 0x01, 0x01,
356  0x00, 0x00
357  };
358 
359  Packet *p = PacketGetFromAlloc();
360  if (unlikely(p == NULL))
361  return 0;
362  ThreadVars tv;
363  DecodeThreadVars dtv;
364 
365  memset(&tv, 0, sizeof(ThreadVars));
366  memset(&dtv, 0, sizeof(DecodeThreadVars));
367 
368  DecodePPPOEDiscovery(&tv, &dtv, p, raw_pppoe, sizeof(raw_pppoe), NULL);
369 
371  SCFree(p);
372  return 1;
373  }
374 
375  SCFree(p);
376  return 0;
377 }
378 
379 /** DecodePPPOEtest05
380  * \brief Valid exaple PADO PPPOE packet taken from RFC2516, but too short for given length
381  * \retval 0 Expected test value
382  */
383 static int DecodePPPOEtest05 (void)
384 {
385 
386  /* example PADI packet taken from RFC2516 */
387  uint8_t raw_pppoe[] = {
388  0x11, 0x07, 0x00, 0x00, 0x00, 0x20, 0x01, 0x01,
389  0x00, 0x00, 0x01, 0x02, 0x00, 0x18, 0x47, 0x6f,
390  0x20, 0x52, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b,
391  0x20, 0x2d, 0x20, 0x65, 0x73, 0x68, 0x73, 0x68
392  };
393 
394  Packet *p = PacketGetFromAlloc();
395  if (unlikely(p == NULL))
396  return 0;
397  ThreadVars tv;
398  DecodeThreadVars dtv;
399 
400  memset(&tv, 0, sizeof(ThreadVars));
401  memset(&dtv, 0, sizeof(DecodeThreadVars));
402 
403  DecodePPPOEDiscovery(&tv, &dtv, p, raw_pppoe, sizeof(raw_pppoe), NULL);
404 
406  SCFree(p);
407  return 1;
408  }
409 
410  SCFree(p);
411  return 0;
412 }
413 
414 /** DecodePPPOEtest06
415  * \brief Check that the macros work as expected. Type and version are
416  * fields of 4 bits length. So they are sharing the same var and the macros
417  * should extract the first 4 bits for version and the second 4 bits for type
418  * \retval 1 Expected test value
419  */
420 static int DecodePPPOEtest06 (void)
421 {
422 
423  PPPOESessionHdr pppoesh;
424  PPPOEDiscoveryHdr pppoedh;
425  pppoesh.pppoe_version_type = 0xAB;
426  pppoedh.pppoe_version_type = 0xCD;
427 
428  if (PPPOE_SESSION_GET_VERSION(&pppoesh) != 0x0A) {
429  printf("Error, PPPOE macro pppoe_session_get_version failed: ");
430  return 0;
431  }
432  if (PPPOE_SESSION_GET_TYPE(&pppoesh) != 0x0B) {
433  printf("Error, PPPOE macro pppoe_session_get_type failed: ");
434  return 0;
435  }
436  if (PPPOE_DISCOVERY_GET_VERSION(&pppoedh) != 0x0C) {
437  printf("Error, PPPOE macro pppoe_discovery_get_version failed: ");
438  return 0;
439  }
440  if (PPPOE_DISCOVERY_GET_TYPE(&pppoedh) != 0x0D) {
441  printf("Error, PPPOE macro pppoe_discovery_get_type failed: ");
442  return 0;
443  }
444 
445  return 1;
446 }
447 #endif /* UNITTESTS */
448 
449 
450 
451 /**
452  * \brief Registers PPPOE unit tests
453  * \todo More PPPOE tests
454  */
456 {
457 #ifdef UNITTESTS
458  UtRegisterTest("DecodePPPOEtest01", DecodePPPOEtest01);
459  UtRegisterTest("DecodePPPOEtest02", DecodePPPOEtest02);
460  UtRegisterTest("DecodePPPOEtest03", DecodePPPOEtest03);
461  UtRegisterTest("DecodePPPOEtest04", DecodePPPOEtest04);
462  UtRegisterTest("DecodePPPOEtest05", DecodePPPOEtest05);
463  UtRegisterTest("DecodePPPOEtest06", DecodePPPOEtest06);
464 #endif /* UNITTESTS */
465 }
466 
467 /**
468  * @}
469  */
int DecodePPPOESession(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint32_t len, PacketQueue *pq)
Main decoding function for PPPOE Session packets.
Definition: decode-pppoe.c:129
#define PPP_VJ_UCOMP
Definition: decode-ppp.h:30
#define PPP_NSCP
Definition: decode-ppp.h:50
#define PPP_HELLO
Definition: decode-ppp.h:43
#define ENGINE_SET_EVENT(p, e)
Definition: decode.h:989
#define SCLogDebug(...)
Definition: util-debug.h:335
#define PPP_PAP
Definition: decode-ppp.h:59
#define PPP_OSI
Definition: decode-ppp.h:36
#define PPPOE_SESSION_HEADER_LEN
Definition: decode-pppoe.h:30
#define ENGINE_ISSET_EVENT(p, e)
Definition: decode.h:1004
#define PPP_OSICP
Definition: decode-ppp.h:49
uint8_t pppoe_code
Definition: decode-pppoe.h:40
#define PPP_SNS
Definition: decode-ppp.h:45
#define unlikely(expr)
Definition: util-optimize.h:35
#define PPPOE_CODE_PADT
Definition: decode-pppoe.h:65
int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint32_t len, PacketQueue *pq)
Main decoding function for PPPOE Discovery packets.
Definition: decode-pppoe.c:50
uint8_t pppoe_version_type
Definition: decode-pppoe.h:39
#define FLOW_QUIET
Definition: flow.h:38
#define PPP_IP
Definition: decode-ppp.h:28
#define PPP_VINES
Definition: decode-ppp.h:42
#define IPV4_GET_RAW_VER(ip4h)
Definition: decode-ipv4.h:94
#define PPPOE_DISCOVERY_GET_VERSION(hdr)
Definition: decode-pppoe.h:34
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq)
Definition: decode-ipv4.c:532
#define PPP_VINESCP
Definition: decode-ppp.h:55
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq)
Definition: decode-ipv6.c:583
#define PPPOE_CODE_PADI
Definition: decode-pppoe.h:61
#define PPP_STIICP
Definition: decode-ppp.h:54
#define PPP_IPX
Definition: decode-ppp.h:35
#define PPP_BRPDU
Definition: decode-ppp.h:40
PPPHdr * ppph
Definition: decode.h:532
PPPOESessionHdr * pppoesh
Definition: decode.h:533
#define PPPOE_DISCOVERY_HEADER_MIN_LEN
Definition: decode-pppoe.h:31
#define PPP_LUXCOM
Definition: decode-ppp.h:44
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Structure to hold thread specific data for all decode modules.
Definition: decode.h:632
uint16_t pppoe_length
Definition: decode-pppoe.h:459
#define PPP_MPLSCP
Definition: decode-ppp.h:57
#define PPPOE_SESSION_GET_VERSION(hdr)
Definition: decode-pppoe.h:32
#define PPPOE_SESSION_GET_TYPE(hdr)
Definition: decode-pppoe.h:33
#define PPPOE_CODE_PADO
Definition: decode-pppoe.h:62
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition: counters.c:163
#define PPP_IPCP
Definition: decode-ppp.h:48
PPPOEDiscoveryHdr * pppoedh
Definition: decode.h:534
#define PPP_VJ_COMP
Definition: decode-ppp.h:34
uint16_t protocol
Definition: decode-pppoe.h:43
#define PPPOE_CODE_PADR
Definition: decode-pppoe.h:63
#define PPP_IPV6
Definition: decode-ppp.h:29
#define IPV6_HEADER_LEN
Definition: decode-ipv6.h:27
#define SCFree(a)
Definition: util-mem.h:322
#define SCNtohs(x)
#define PPP_DECNETCP
Definition: decode-ppp.h:51
#define PPP_NS
Definition: decode-ppp.h:37
#define PPP_MPLS_UCAST
Definition: decode-ppp.h:46
#define PPP_STII
Definition: decode-ppp.h:41
#define PPP_DECNET
Definition: decode-ppp.h:38
#define PPP_CHAP
Definition: decode-ppp.h:61
#define PPPOE_CODE_PADS
Definition: decode-pppoe.h:64
void FlowShutdown(void)
shutdown the flow engine
Definition: flow.c:667
#define PPP_APPLE
Definition: decode-ppp.h:39
#define PPP_IPV6CP
Definition: decode-ppp.h:56
void DecodePPPOERegisterTests(void)
Registers PPPOE unit tests.
Definition: decode-pppoe.c:455
#define PPP_APPLECP
Definition: decode-ppp.h:52
uint16_t counter_pppoe
Definition: decode.h:663
uint16_t pppoe_length
Definition: decode-pppoe.h:42
uint8_t len
Per thread variable structure.
Definition: threadvars.h:57
#define PPP_IPXCP
Definition: decode-ppp.h:53
uint16_t session_id
Definition: decode-pppoe.h:41
#define PPP_MPLS_MCAST
Definition: decode-ppp.h:47
#define PPPOE_DISCOVERY_GET_TYPE(hdr)
Definition: decode-pppoe.h:35
#define IPV4_HEADER_LEN
Definition: decode-ipv4.h:28
#define PPP_LQM
Definition: decode-ppp.h:60
#define PPP_LCP
Definition: decode-ppp.h:58
#define ENGINE_SET_INVALID_EVENT(p, e)
Definition: decode.h:997
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:141
void FlowInitConfig(char quiet)
initialize the configuration
Definition: flow.c:512