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  */
51  const uint8_t *pkt, uint32_t len, PacketQueue *pq)
52 {
53  StatsIncr(tv, dtv->counter_pppoe);
54 
57  return TM_ECODE_FAILED;
58  }
59 
60  p->pppoedh = (PPPOEDiscoveryHdr *)pkt;
61  if (p->pppoedh == NULL)
62  return TM_ECODE_FAILED;
63 
64  /* parse the PPPOE code */
65  switch (p->pppoedh->pppoe_code)
66  {
67  case PPPOE_CODE_PADI:
68  break;
69  case PPPOE_CODE_PADO:
70  break;
71  case PPPOE_CODE_PADR:
72  break;
73  case PPPOE_CODE_PADS:
74  break;
75  case PPPOE_CODE_PADT:
76  break;
77  default:
78  SCLogDebug("unknown PPPOE code: 0x%0"PRIX8"", p->pppoedh->pppoe_code);
80  return TM_ECODE_OK;
81  }
82 
83  /* parse any tags we have in the packet */
84 
85  uint32_t tag_length = 0;
86  PPPOEDiscoveryTag* pppoedt = (PPPOEDiscoveryTag*) (p->pppoedh + PPPOE_DISCOVERY_HEADER_MIN_LEN);
87 
88  uint32_t pppoe_length = SCNtohs(p->pppoedh->pppoe_length);
89  uint32_t packet_length = len - PPPOE_DISCOVERY_HEADER_MIN_LEN ;
90 
91  SCLogDebug("pppoe_length %"PRIu32", packet_length %"PRIu32"",
92  pppoe_length, packet_length);
93 
94  if (pppoe_length > packet_length) {
95  SCLogDebug("malformed PPPOE tags");
97  return TM_ECODE_OK;
98  }
99 
100  while (pppoedt < (PPPOEDiscoveryTag*) (pkt + (len - sizeof(PPPOEDiscoveryTag))) && pppoe_length >=4 && packet_length >=4)
101  {
102 #ifdef DEBUG
103  uint16_t tag_type = SCNtohs(pppoedt->pppoe_tag_type);
104 #endif
105  tag_length = SCNtohs(pppoedt->pppoe_tag_length);
106 
107  SCLogDebug ("PPPoE Tag type %x, length %"PRIu32, tag_type, tag_length);
108 
109  if (pppoe_length >= (4 + tag_length)) {
110  pppoe_length -= (4 + tag_length);
111  } else {
112  pppoe_length = 0; // don't want an underflow
113  }
114 
115  if (packet_length >= 4 + tag_length) {
116  packet_length -= (4 + tag_length);
117  } else {
118  packet_length = 0; // don't want an underflow
119  }
120 
121  pppoedt = pppoedt + (4 + tag_length);
122  }
123 
124  return TM_ECODE_OK;
125 }
126 
127 /**
128  * \brief Main decoding function for PPPOE Session packets
129  */
131  const uint8_t *pkt, uint32_t len, PacketQueue *pq)
132 {
133  StatsIncr(tv, dtv->counter_pppoe);
134 
135  if (len < PPPOE_SESSION_HEADER_LEN) {
137  return TM_ECODE_FAILED;
138  }
139 
140  p->pppoesh = (PPPOESessionHdr *)pkt;
141  if (p->pppoesh == NULL)
142  return TM_ECODE_FAILED;
143 
144  SCLogDebug("PPPOE VERSION %" PRIu32 " TYPE %" PRIu32 " CODE %" PRIu32 " SESSIONID %" PRIu32 " LENGTH %" PRIu32 "",
146 
147  /* can't use DecodePPP() here because we only get a single 2-byte word to indicate protocol instead of the full PPP header */
148 
149  if (SCNtohs(p->pppoesh->pppoe_length) > 0) {
150  /* decode contained PPP packet */
151 
152  switch (SCNtohs(p->pppoesh->protocol))
153  {
154  case PPP_VJ_COMP:
155  case PPP_IPX:
156  case PPP_OSI:
157  case PPP_NS:
158  case PPP_DECNET:
159  case PPP_APPLE:
160  case PPP_BRPDU:
161  case PPP_STII:
162  case PPP_VINES:
163  case PPP_HELLO:
164  case PPP_LUXCOM:
165  case PPP_SNS:
166  case PPP_MPLS_UCAST:
167  case PPP_MPLS_MCAST:
168  case PPP_IPCP:
169  case PPP_OSICP:
170  case PPP_NSCP:
171  case PPP_DECNETCP:
172  case PPP_APPLECP:
173  case PPP_IPXCP:
174  case PPP_STIICP:
175  case PPP_VINESCP:
176  case PPP_IPV6CP:
177  case PPP_MPLSCP:
178  case PPP_LCP:
179  case PPP_PAP:
180  case PPP_LQM:
181  case PPP_CHAP:
183  break;
184 
185  case PPP_VJ_UCOMP:
186 
189  return TM_ECODE_OK;
190  }
191  if (unlikely(len > PPPOE_SESSION_HEADER_LEN + USHRT_MAX)) {
192  return TM_ECODE_FAILED;
193  }
194 
195  if(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + PPPOE_SESSION_HEADER_LEN)) == 4) {
196  DecodeIPV4(tv, dtv, p, pkt + PPPOE_SESSION_HEADER_LEN, len - PPPOE_SESSION_HEADER_LEN, pq );
197  }
198  break;
199 
200  case PPP_IP:
203  return TM_ECODE_OK;
204  }
205  if (unlikely(len > PPPOE_SESSION_HEADER_LEN + USHRT_MAX)) {
206  return TM_ECODE_FAILED;
207  }
208 
209  DecodeIPV4(tv, dtv, p, pkt + PPPOE_SESSION_HEADER_LEN, len - PPPOE_SESSION_HEADER_LEN, pq );
210  break;
211 
212  /* PPP IPv6 was not tested */
213  case PPP_IPV6:
216  return TM_ECODE_OK;
217  }
218  if (unlikely(len > PPPOE_SESSION_HEADER_LEN + USHRT_MAX)) {
219  return TM_ECODE_FAILED;
220  }
221 
222  DecodeIPV6(tv, dtv, p, pkt + PPPOE_SESSION_HEADER_LEN, len - PPPOE_SESSION_HEADER_LEN, pq );
223  break;
224 
225  default:
226  SCLogDebug("unknown PPP protocol: %" PRIx32 "",SCNtohs(p->ppph->protocol));
228  return TM_ECODE_OK;
229  }
230  }
231  return TM_ECODE_OK;
232 }
233 
234 #ifdef UNITTESTS
235 /** DecodePPPOEtest01
236  * \brief Decode malformed PPPOE packet (too short)
237  * \retval 1 Expected test value
238  */
239 static int DecodePPPOEtest01 (void)
240 {
241 
242  uint8_t raw_pppoe[] = { 0x11, 0x00, 0x00, 0x00, 0x00 };
243  Packet *p = PacketGetFromAlloc();
244  if (unlikely(p == NULL))
245  return 0;
246  ThreadVars tv;
247  DecodeThreadVars dtv;
248 
249  memset(&tv, 0, sizeof(ThreadVars));
250  memset(&dtv, 0, sizeof(DecodeThreadVars));
251 
252  DecodePPPOESession(&tv, &dtv, p, raw_pppoe, sizeof(raw_pppoe), NULL);
253 
255  SCFree(p);
256  return 1;
257  }
258 
259  SCFree(p);
260  return 0;
261 }
262 
263 /** DecodePPPOEtest02
264  * \brief Valid PPPOE packet - check the invalid ICMP type encapsulated is flagged
265  * \retval 0 Expected test value
266  */
267 static int DecodePPPOEtest02 (void)
268 {
269 
270  uint8_t raw_pppoe[] = {
271  0x11, 0x00, 0x00, 0x01, 0x00, 0x40, 0x00, 0x21,
272  0x45, 0x00, 0x00, 0x3c, 0x05, 0x5c, 0x00, 0x00,
273  0x20, 0x01, 0xff, 0x30, 0xc0, 0xa8, 0x0a, 0x7f,
274  0xc0, 0xa8, 0x0a, 0x65, 0xab, 0xcd, 0x16, 0x5e,
275  0x02, 0x00, 0x37, 0x00, 0x41, 0x42, 0x43, 0x44,
276  0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
277  0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54,
278  0x55, 0x56, 0x57, 0x41, 0x42, 0x43, 0x44, 0x45,
279  0x46, 0x47, 0x48, 0x49 };
280 
281  Packet *p = PacketGetFromAlloc();
282  if (unlikely(p == NULL))
283  return 0;
284  ThreadVars tv;
285  DecodeThreadVars dtv;
286  int ret = 0;
287 
288  memset(&tv, 0, sizeof(ThreadVars));
289  memset(&dtv, 0, sizeof(DecodeThreadVars));
290 
292 
293  DecodePPPOESession(&tv, &dtv, p, raw_pppoe, sizeof(raw_pppoe), NULL);
294 
296  goto end;
297  }
298 
299  // and we insist that the invalid ICMP encapsulated (type 0xab, code 0xcd) is flagged
300 
302  goto end;
303  }
304 
305  ret = 1;
306 end:
307  FlowShutdown();
308  SCFree(p);
309  return ret;
310 }
311 
312 
313 /** DecodePPPOEtest03
314  * \brief Valid example PADO packet PPPOE packet taken from RFC2516
315  * \retval 0 Expected test value
316  */
317 static int DecodePPPOEtest03 (void)
318 {
319 
320  /* example PADO packet taken from RFC2516 */
321  uint8_t raw_pppoe[] = {
322  0x11, 0x07, 0x00, 0x00, 0x00, 0x20, 0x01, 0x01,
323  0x00, 0x00, 0x01, 0x02, 0x00, 0x18, 0x47, 0x6f,
324  0x20, 0x52, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b,
325  0x20, 0x2d, 0x20, 0x65, 0x73, 0x68, 0x73, 0x68,
326  0x65, 0x73, 0x68, 0x6f, 0x6f, 0x74
327  };
328 
329  Packet *p = PacketGetFromAlloc();
330  if (unlikely(p == NULL))
331  return 0;
332  ThreadVars tv;
333  DecodeThreadVars dtv;
334 
335  memset(&tv, 0, sizeof(ThreadVars));
336  memset(&dtv, 0, sizeof(DecodeThreadVars));
337 
338  DecodePPPOEDiscovery(&tv, &dtv, p, raw_pppoe, sizeof(raw_pppoe), NULL);
339  if (p->pppoedh == NULL) {
340  SCFree(p);
341  return 0;
342  }
343 
344  SCFree(p);
345  return 1;
346 }
347 
348 /** DecodePPPOEtest04
349  * \brief Valid example PPPOE packet taken from RFC2516 - but with wrong PPPOE code
350  * \retval 1 Expected test value
351  */
352 static int DecodePPPOEtest04 (void)
353 {
354 
355  /* example PADI packet taken from RFC2516, but with wrong code */
356  uint8_t raw_pppoe[] = {
357  0x11, 0xbb, 0x00, 0x00, 0x00, 0x04, 0x01, 0x01,
358  0x00, 0x00
359  };
360 
361  Packet *p = PacketGetFromAlloc();
362  if (unlikely(p == NULL))
363  return 0;
364  ThreadVars tv;
365  DecodeThreadVars dtv;
366 
367  memset(&tv, 0, sizeof(ThreadVars));
368  memset(&dtv, 0, sizeof(DecodeThreadVars));
369 
370  DecodePPPOEDiscovery(&tv, &dtv, p, raw_pppoe, sizeof(raw_pppoe), NULL);
371 
373  SCFree(p);
374  return 1;
375  }
376 
377  SCFree(p);
378  return 0;
379 }
380 
381 /** DecodePPPOEtest05
382  * \brief Valid exaple PADO PPPOE packet taken from RFC2516, but too short for given length
383  * \retval 0 Expected test value
384  */
385 static int DecodePPPOEtest05 (void)
386 {
387 
388  /* example PADI packet taken from RFC2516 */
389  uint8_t raw_pppoe[] = {
390  0x11, 0x07, 0x00, 0x00, 0x00, 0x20, 0x01, 0x01,
391  0x00, 0x00, 0x01, 0x02, 0x00, 0x18, 0x47, 0x6f,
392  0x20, 0x52, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b,
393  0x20, 0x2d, 0x20, 0x65, 0x73, 0x68, 0x73, 0x68
394  };
395 
396  Packet *p = PacketGetFromAlloc();
397  if (unlikely(p == NULL))
398  return 0;
399  ThreadVars tv;
400  DecodeThreadVars dtv;
401 
402  memset(&tv, 0, sizeof(ThreadVars));
403  memset(&dtv, 0, sizeof(DecodeThreadVars));
404 
405  DecodePPPOEDiscovery(&tv, &dtv, p, raw_pppoe, sizeof(raw_pppoe), NULL);
406 
408  SCFree(p);
409  return 1;
410  }
411 
412  SCFree(p);
413  return 0;
414 }
415 
416 /** DecodePPPOEtest06
417  * \brief Check that the macros work as expected. Type and version are
418  * fields of 4 bits length. So they are sharing the same var and the macros
419  * should extract the first 4 bits for version and the second 4 bits for type
420  * \retval 1 Expected test value
421  */
422 static int DecodePPPOEtest06 (void)
423 {
424 
425  PPPOESessionHdr pppoesh;
426  PPPOEDiscoveryHdr pppoedh;
427  pppoesh.pppoe_version_type = 0xAB;
428  pppoedh.pppoe_version_type = 0xCD;
429 
430  if (PPPOE_SESSION_GET_VERSION(&pppoesh) != 0x0A) {
431  printf("Error, PPPOE macro pppoe_session_get_version failed: ");
432  return 0;
433  }
434  if (PPPOE_SESSION_GET_TYPE(&pppoesh) != 0x0B) {
435  printf("Error, PPPOE macro pppoe_session_get_type failed: ");
436  return 0;
437  }
438  if (PPPOE_DISCOVERY_GET_VERSION(&pppoedh) != 0x0C) {
439  printf("Error, PPPOE macro pppoe_discovery_get_version failed: ");
440  return 0;
441  }
442  if (PPPOE_DISCOVERY_GET_TYPE(&pppoedh) != 0x0D) {
443  printf("Error, PPPOE macro pppoe_discovery_get_type failed: ");
444  return 0;
445  }
446 
447  return 1;
448 }
449 #endif /* UNITTESTS */
450 
451 
452 
453 /**
454  * \brief Registers PPPOE unit tests
455  * \todo More PPPOE tests
456  */
458 {
459 #ifdef UNITTESTS
460  UtRegisterTest("DecodePPPOEtest01", DecodePPPOEtest01);
461  UtRegisterTest("DecodePPPOEtest02", DecodePPPOEtest02);
462  UtRegisterTest("DecodePPPOEtest03", DecodePPPOEtest03);
463  UtRegisterTest("DecodePPPOEtest04", DecodePPPOEtest04);
464  UtRegisterTest("DecodePPPOEtest05", DecodePPPOEtest05);
465  UtRegisterTest("DecodePPPOEtest06", DecodePPPOEtest06);
466 #endif /* UNITTESTS */
467 }
468 
469 /**
470  * @}
471  */
#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:992
#define SCLogDebug(...)
Definition: util-debug.h:335
#define PPP_PAP
Definition: decode-ppp.h:59
int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len, PacketQueue *pq)
Main decoding function for PPPOE Discovery packets.
Definition: decode-pppoe.c:50
#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:1007
#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
int DecodePPPOESession(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len, PacketQueue *pq)
Main decoding function for PPPOE Session packets.
Definition: decode-pppoe.c:130
#define PPPOE_CODE_PADT
Definition: decode-pppoe.h:65
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
#define PPP_VINESCP
Definition: decode-ppp.h:55
#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:461
#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:168
#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
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len, PacketQueue *pq)
Definition: decode-ipv6.c:585
#define IPV6_HEADER_LEN
Definition: decode-ipv6.h:27
#define SCFree(a)
Definition: util-mem.h:322
#define SCNtohs(x)
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len, PacketQueue *pq)
Definition: decode-ipv4.c:532
#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:670
#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:457
#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:1000
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:141
void FlowInitConfig(char quiet)
initialize the configuration
Definition: flow.c:515