p2pd: add UseTTLDecrement configuration setting
[olsrd.git] / lib / p2pd / src / p2pd.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright
11  *   notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in
14  *   the documentation and/or other materials provided with the
15  *   distribution.
16  * * Neither the name of olsr.org, olsrd nor the names of its
17  *   contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Visit http://www.olsr.org for more information.
34  *
35  * If you find this software useful feel free to make a donation
36  * to the project. For more information see the website or contact
37  * the copyright holders.
38  *
39  */
40
41
42 #include "p2pd.h"
43
44 /* System includes */
45 #include <stddef.h>             /* NULL */
46 #include <sys/types.h>          /* ssize_t */
47 #include <string.h>             /* strerror() */
48 #include <stdarg.h>             /* va_list, va_start, va_end */
49 #include <errno.h>              /* errno */
50 #include <assert.h>             /* assert() */
51 #include <unistd.h>
52 #include <fcntl.h>
53 #include <linux/if_ether.h>     /* ETH_P_IP */
54 #include <linux/if_packet.h>    /* struct sockaddr_ll, PACKET_MULTICAST */
55 #include <signal.h>             /* sigset_t, sigfillset(), sigdelset(), SIGINT */
56 #include <netinet/ip.h>         /* struct ip */
57 #include <netinet/udp.h>        /* struct udphdr */
58 #include <unistd.h>             /* close() */
59
60 #include <netinet/in.h>
61 #include <netinet/ip6.h>
62
63 #include <time.h>
64
65 /* OLSRD includes */
66 #include "plugin_util.h"        /* set_plugin_int */
67 #include "defs.h"               /* olsr_cnf, //OLSR_PRINTF */
68 #include "ipcalc.h"
69 #include "olsr.h"               /* //OLSR_PRINTF */
70 #include "mid_set.h"            /* mid_lookup_main_addr() */
71 #include "link_set.h"           /* get_best_link_to_neighbor() */
72 #include "net_olsr.h"           /* ipequal */
73 #include "parser.h"
74
75 /* plugin includes */
76 #include "NetworkInterfaces.h"  /* NonOlsrInterface,
77                                    CreateBmfNetworkInterfaces(),
78                                    CloseBmfNetworkInterfaces() */
79 //#include "Address.h"          /* IsMulticast() */
80 #include "Packet.h"             /* ENCAP_HDR_LEN,
81                                    BMF_ENCAP_TYPE,
82                                    BMF_ENCAP_LEN etc. */
83 #include "PacketHistory.h"
84 #include "dllist.h"
85
86 int P2pdTtl                        = 0;
87 int P2pdUseHash                    = 0;  /* Switch off hash filter by default */
88 int P2pdUseTtlDecrement            = 0;  /* No TTL decrement by default */
89 int P2pdDuplicateTimeout           = P2PD_VALID_TIME;
90
91 /* List of UDP destination address and port information */
92 struct UdpDestPort *                 UdpDestPortList = NULL;
93
94 /* List of filter entries to check for duplicate messages
95  */
96 struct node *                        dupFilterHead = NULL;
97 struct node *                        dupFilterTail = NULL;
98
99 bool is_broadcast(const struct sockaddr_in addr);
100 bool is_multicast(const struct sockaddr_in addr);
101 char * get_ipv4_str(uint32_t address, char *s, size_t maxlen);
102 char * get_ipv6_str(unsigned char* address, char *s, size_t maxlen);
103 #ifdef INCLUDE_DEBUG_OUTPUT
104 void dump_packet(unsigned char* packet, int length);
105 #endif /* INCLUDE_DEBUG_OUTPUT */
106 bool check_and_mark_recent_packet(unsigned char *data, int len);
107
108 /* -------------------------------------------------------------------------
109  * Function   : PacketReceivedFromOLSR
110  * Description: Handle a received packet from a OLSR message
111  * Input      : ipPacket into an unsigned char and the lenght of the packet
112  * Output     : none
113  * Return     : none
114  * Data Used  : BmfInterfaces
115  * ------------------------------------------------------------------------- */
116 static void
117 PacketReceivedFromOLSR(unsigned char *encapsulationUdpData, int len)
118 {
119   struct ip *ipHeader;        /* IP header inside the encapsulated IP packet */
120   struct ip6_hdr *ip6Header;  /* IP header inside the encapsulated IP packet */
121   struct udphdr *udpHeader;
122   struct NonOlsrInterface *walker;
123   int stripped_len = 0;
124   union olsr_ip_addr destAddr;
125   int destPort;
126   bool isInList = false;
127
128   ipHeader = (struct ip *) ARM_NOWARN_ALIGN(encapsulationUdpData);
129   ip6Header = (struct ip6_hdr *) ARM_NOWARN_ALIGN(encapsulationUdpData);
130   //OLSR_DEBUG(LOG_PLUGINS, "P2PD PLUGIN got packet from OLSR message\n");
131
132   if (check_and_mark_recent_packet(encapsulationUdpData, len))
133     return;
134
135   /* Check with each network interface what needs to be done on it */
136   for (walker = nonOlsrInterfaces; walker != NULL; walker = walker->next) {
137     /* To a non-OLSR interface: unpack encapsulated IP packet and forward it */
138     if (walker->olsrIntf == NULL) {
139       int nBytesWritten;
140       struct sockaddr_ll dest;
141
142       memset(&dest, 0, sizeof(dest));
143       dest.sll_family = AF_PACKET;
144       if ((encapsulationUdpData[0] & 0xf0) == 0x40) {
145         dest.sll_protocol = htons(ETH_P_IP);
146         stripped_len = ntohs(ipHeader->ip_len);
147       }
148
149       if ((encapsulationUdpData[0] & 0xf0) == 0x60) {
150         dest.sll_protocol = htons(ETH_P_IPV6);
151         stripped_len = 40 + ntohs(ip6Header->ip6_plen); // IPv6 Header size (40)
152                                                         // + payload_len
153       }
154
155       // Sven-Ola: Don't know how to handle the "stripped_len is uninitialized"
156       // condition, maybe exit(1) is better...?
157       if (0 == stripped_len)
158         return;
159
160       //TODO: if packet is not IP die here
161
162       if (stripped_len > len) {
163       }
164
165       dest.sll_ifindex = if_nametoindex(walker->ifName);
166       dest.sll_halen = IFHWADDRLEN;
167
168       if (olsr_cnf->ip_version == AF_INET) {
169         /* Use all-ones as destination MAC address. When the IP destination is
170          * a multicast address, the destination MAC address should normally also
171          * be a multicast address. E.g., when the destination IP is 224.0.0.1,
172          * the destination MAC should be 01:00:5e:00:00:01. However, it does not
173          * seem to matter when the destination MAC address is set to all-ones
174          * in that case.
175          */
176
177         if (IsMulticastv4(ipHeader)) {
178           in_addr_t addr = ntohl(ipHeader->ip_dst.s_addr);
179
180           dest.sll_addr[0] = 0x01;
181           dest.sll_addr[1] = 0x00;
182           dest.sll_addr[2] = 0x5E;
183           dest.sll_addr[3] = (addr >> 16) & 0x7F;
184           dest.sll_addr[4] = (addr >>  8) & 0xFF;
185           dest.sll_addr[5] = addr & 0xFF;
186         } else {
187           /* broadcast or whatever */
188           memset(dest.sll_addr, 0xFF, IFHWADDRLEN);
189         }
190       } else /*(olsr_cnf->ip_version == AF_INET6) */ {
191         if (IsMulticastv6(ip6Header)) {
192           dest.sll_addr[0] = 0x33;
193           dest.sll_addr[1] = 0x33;
194           dest.sll_addr[2] = ip6Header->ip6_dst.s6_addr[12];
195           dest.sll_addr[3] = ip6Header->ip6_dst.s6_addr[13];
196           dest.sll_addr[4] = ip6Header->ip6_dst.s6_addr[14];
197           dest.sll_addr[5] = ip6Header->ip6_dst.s6_addr[15];
198         }
199       }
200
201       if (olsr_cnf->ip_version == AF_INET) {
202         // Determine the IP address and the port from the header information
203         if (ipHeader->ip_p == SOL_UDP && !IsIpv4Fragment(ipHeader)) {
204           udpHeader = (struct udphdr*) ARM_NOWARN_ALIGN((encapsulationUdpData +
205                                        GetIpHeaderLength(encapsulationUdpData)));
206           destAddr.v4.s_addr = ipHeader->ip_dst.s_addr;
207           destPort = htons(udpHeader->dest);
208           isInList = InUdpDestPortList(AF_INET, &destAddr, destPort);
209 #ifdef INCLUDE_DEBUG_OUTPUT
210           if (!isInList) {
211             char tmp[32];
212             OLSR_PRINTF(1,
213                         "%s: Not in dest/port list: %s:%d\n",
214                         PLUGIN_NAME_SHORT,
215                         get_ipv4_str(destAddr.v4.s_addr,
216                                      tmp,
217                                      sizeof(tmp)),
218                         destPort);
219           }
220 #endif /* INCLUDE_DEBUG_OUTPUT */
221         }
222       } else /* (olsr_cnf->ip_version == AF_INET6) */ {
223         if (ip6Header->ip6_nxt == SOL_UDP && !IsIpv6Fragment(ip6Header)) {
224           udpHeader = (struct udphdr*) ARM_NOWARN_ALIGN((encapsulationUdpData + 40));
225           memcpy(&destAddr.v6, &ip6Header->ip6_dst, sizeof(struct in6_addr));
226           destPort = htons(udpHeader->dest);
227           isInList = InUdpDestPortList(AF_INET6, &destAddr, destPort);
228 #ifdef INCLUDE_DEBUG_OUTPUT
229           if (!isInList) {
230             char tmp[64];
231             OLSR_PRINTF(1,
232                         "%s: Not in dest/port list: %s:%d\n",
233                         PLUGIN_NAME_SHORT,
234                         get_ipv6_str(destAddr.v6.s6_addr,
235                                      tmp,
236                                      sizeof(tmp)),
237                         destPort);
238           }
239 #endif /* INCLUDE_DEBUG_OUTPUT */
240         }
241       }
242
243       if (!isInList) {
244         /* Address/port combination of this packet is not in the UDP dest/port
245          * list and will therefore be suppressed. I.e. just continue with the
246          * next interface to emit on.
247          */
248         continue;
249       }
250       
251       nBytesWritten = sendto(walker->capturingSkfd,
252                              encapsulationUdpData,
253                              stripped_len,
254                              0,
255                              (struct sockaddr *)&dest,
256                              sizeof(dest));
257       if (nBytesWritten != stripped_len) {
258         P2pdPError("sendto() error forwarding unpacked encapsulated pkt on \"%s\"",
259                    walker->ifName);
260       } else {
261
262         //OLSR_PRINTF(
263         //  2,
264         //  "%s: --> unpacked and forwarded on \"%s\"\n",
265         //  PLUGIN_NAME_SHORT,
266         //  walker->ifName);
267       }
268     }                           /* if (walker->olsrIntf == NULL) */
269   }
270 }                               /* PacketReceivedFromOLSR */
271
272 /* Highest-numbered open socket file descriptor. To be used as first
273  * parameter in calls to select(...).
274  */
275 int HighestSkfd = -1;
276
277 /* Set of socket file descriptors */
278 fd_set InputSet;
279
280 /* -------------------------------------------------------------------------
281  * Function   : p2pd_message_seen
282  * Description: Check whether the current message has been seen before
283  * Input      : head - start of the list to check for the message
284  *              tail - end of the list to check for the message
285  *              m    - message to check for in the list
286  * Output     : none
287  * Return     : true if message was found, false otherwise
288  * Data Used  : P2pdDuplicateTimeout
289  * ------------------------------------------------------------------------- */
290 bool
291 p2pd_message_seen(struct node **head, struct node **tail, union olsr_message *m)
292 {
293   struct node * curr;
294   time_t now;
295
296   now = time(NULL);
297
298   // Check whether any entries have aged
299   curr = *head;
300   while (curr) {
301     struct DupFilterEntry *filter;
302     struct node * next = curr->next; // Save the current pointer since curr may
303                                      // be destroyed
304
305     filter = (struct DupFilterEntry*)curr->data;
306
307     if ((filter->creationtime + P2pdDuplicateTimeout) < now)
308       remove_node(head, tail, curr, true);
309
310     // Skip to the next element
311     curr = next;
312   }
313
314   // Now check whether there are any duplicates
315   for (curr = *head; curr; curr = curr->next) {
316     struct DupFilterEntry *filter = (struct DupFilterEntry*)curr->data;
317
318     if (olsr_cnf->ip_version == AF_INET) {
319       if (filter->address.v4.s_addr == m->v4.originator &&
320           filter->msgtype == m->v4.olsr_msgtype &&
321           filter->seqno == m->v4.seqno) {
322           return true;
323       }
324     } else /* if (olsr_cnf->ip_version == AF_INET6) */ {
325       if (memcmp(filter->address.v6.s6_addr,
326                  m->v6.originator.s6_addr,
327                  sizeof(m->v6.originator.s6_addr)) == 0 &&
328           filter->msgtype == m->v6.olsr_msgtype &&
329           filter->seqno == m->v6.seqno) {
330           return true;
331       }
332     }
333   }
334
335   return false;
336 }
337
338 /* -------------------------------------------------------------------------
339  * Function   : p2pd_store_message
340  * Description: Store a new message in the duplicate message check list
341  * Input      : head - start of the list to add the message to
342  *              tail - end of the list to add the message to
343  *              m    - message to add to the list
344  * Output     : none
345  * Return     : nothing
346  * Data Used  : none
347  * ------------------------------------------------------------------------- */
348 void
349 p2pd_store_message(struct node **head, struct node **tail, union olsr_message *m)
350 {
351   time_t now;
352
353   // Store a message into the database
354   struct DupFilterEntry *new_dup = calloc(1, sizeof(struct DupFilterEntry));
355   if (new_dup == NULL) {
356     OLSR_PRINTF(1, "%s: Out of memory\n", PLUGIN_NAME_SHORT);
357     return;
358   }
359
360   now = time(NULL);
361
362   new_dup->creationtime = now;
363   if (olsr_cnf->ip_version == AF_INET) {
364     new_dup->address.v4.s_addr = m->v4.originator;
365     new_dup->msgtype           = m->v4.olsr_msgtype;
366     new_dup->seqno             = m->v4.seqno;
367   } else /* if (olsr_cnf->ip_version == AF_INET6) */ {
368     memcpy(new_dup->address.v6.s6_addr,
369            m->v6.originator.s6_addr,
370            sizeof(m->v6.originator.s6_addr));
371     new_dup->msgtype           = m->v6.olsr_msgtype;
372     new_dup->seqno             = m->v6.seqno;
373   }
374
375   // Add the element to the head of the list
376   append_node(head, tail, new_dup);
377 }
378
379 /* -------------------------------------------------------------------------
380  * Function   : p2pd_is_duplicate_message
381  * Description: Check whether the specified message is a duplicate
382  * Input      : msg - message to check for in the list of duplicate messages
383  * Output     : none
384  * Return     : true if message was found, false otherwise
385  * Data Used  : none
386  * ------------------------------------------------------------------------- */
387 bool
388 p2pd_is_duplicate_message(union olsr_message *msg)
389 {
390   if(p2pd_message_seen(&dupFilterHead, &dupFilterTail, msg)) {
391     return true;
392   }
393
394   p2pd_store_message(&dupFilterHead, &dupFilterTail, msg);
395
396   return false;
397 }
398
399 /* -------------------------------------------------------------------------
400  * Function   : olsr_parser
401  * Description: Function to be passed to the parser engine. This function
402  *              processes the incoming message and passes it on if necessary.
403  * Input      : m      - message to parse
404  *              in_if  - interface to use (unused in this application)
405  *              ipaddr - IP-address to use (unused in this application)
406  * Output     : none
407  * Return     : false if message should be supressed, true otherwise
408  * Data Used  : none
409  * ------------------------------------------------------------------------- */
410 bool
411 olsr_parser(union olsr_message *m,
412             struct interface *in_if __attribute__ ((unused)),
413             union olsr_ip_addr *ipaddr __attribute__ ((unused)))
414 {
415   union olsr_ip_addr originator;
416   int size;
417
418   //OLSR_DEBUG(LOG_PLUGINS, "P2PD PLUGIN: Received msg in parser\n");
419
420         /* Fetch the originator of the messsage */
421   if (olsr_cnf->ip_version == AF_INET) {
422     memcpy(&originator, &m->v4.originator, olsr_cnf->ipsize);
423     size = ntohs(m->v4.olsr_msgsize);
424   } else {
425     memcpy(&originator, &m->v6.originator, olsr_cnf->ipsize);
426     size = ntohs(m->v6.olsr_msgsize);
427   }
428
429   /* Check if message originated from this node.
430    *         If so - back off */
431   if (ipequal(&originator, &olsr_cnf->main_addr))
432     return false;          /* Don't forward either */
433
434   /* Check for duplicate messages for processing */
435   if (p2pd_is_duplicate_message(m))
436     return true;  /* Don't process but allow to be forwarded */
437
438   if (olsr_cnf->ip_version == AF_INET) {
439     PacketReceivedFromOLSR((unsigned char *)&m->v4.message, size - 12);
440   } else {
441     PacketReceivedFromOLSR((unsigned char *)&m->v6.message, size - 12 - 96);
442   }
443
444         return true;
445 }
446
447 /* -------------------------------------------------------------------------
448  * Function   : olsr_p2pd_gen
449  * Description: Sends a packet in the OLSR network
450  * Input      : packet - packet to send in the OLSR network
451  *              len    - length of the packet to send
452  * Output     : none
453  * Return     : nothing
454  * Data Used  : none
455  * ------------------------------------------------------------------------- */
456 void
457 olsr_p2pd_gen(unsigned char *packet, int len)
458 {
459   /* send buffer: huge */
460   char buffer[10240];
461   int aligned_size;
462   union olsr_message *message = (union olsr_message *)buffer;
463   struct interface *ifn;
464
465   aligned_size=len;
466
467   if ((aligned_size % 4) != 0) {
468     aligned_size = (aligned_size - (aligned_size % 4)) + 4;
469   }
470
471   /* fill message */
472   if (olsr_cnf->ip_version == AF_INET) {
473     /* IPv4 */
474     message->v4.olsr_msgtype  = P2PD_MESSAGE_TYPE;
475     message->v4.olsr_vtime    = reltime_to_me(P2PD_VALID_TIME * MSEC_PER_SEC);
476     memcpy(&message->v4.originator, &olsr_cnf->main_addr, olsr_cnf->ipsize);
477     message->v4.ttl           = P2pdTtl ? P2pdTtl : MAX_TTL;
478     message->v4.hopcnt        = 0;
479     message->v4.seqno         = htons(get_msg_seqno());
480     message->v4.olsr_msgsize  = htons(aligned_size + 12);
481     memset(&message->v4.message, 0, aligned_size);
482     memcpy(&message->v4.message, packet, len);
483     aligned_size = aligned_size + 12;
484   } else /* if (olsr_cnf->ip_version == AF_INET6) */ {
485     /* IPv6 */
486     message->v6.olsr_msgtype  = P2PD_MESSAGE_TYPE;
487     message->v6.olsr_vtime    = reltime_to_me(P2PD_VALID_TIME * MSEC_PER_SEC);
488     memcpy(&message->v6.originator, &olsr_cnf->main_addr, olsr_cnf->ipsize);
489     message->v6.ttl           = P2pdTtl ? P2pdTtl : MAX_TTL;
490     message->v6.hopcnt        = 0;
491     message->v6.seqno         = htons(get_msg_seqno());
492     message->v6.olsr_msgsize  = htons(aligned_size + 12 + 96);
493     memset(&message->v6.message, 0, aligned_size);
494     memcpy(&message->v6.message, packet, len);
495     aligned_size = aligned_size + 12 + 96;
496   }
497
498   /* looping through interfaces */
499   for (ifn = ifnet; ifn; ifn = ifn->int_next) {
500     //OLSR_PRINTF(1, "%s: Generating packet - [%s]\n", PLUGIN_NAME_SHORT, ifn->int_name);
501
502     if (net_outbuffer_push(ifn, message, aligned_size) != aligned_size) {
503       /* send data and try again */
504       net_output(ifn);
505       if (net_outbuffer_push(ifn, message, aligned_size) != aligned_size) {
506         //OLSR_PRINTF(1, "%s: could not send on interface: %s\n", PLUGIN_NAME_SHORT, ifn->int_name);
507       }
508     }
509   }
510 }
511
512 /* -------------------------------------------------------------------------
513  * Function   : P2pdPError
514  * Description: Prints an error message at OLSR debug level 1.
515  *              First the plug-in name is printed. Then (if format is not NULL
516  *              and *format is not empty) the arguments are printed, followed
517  *              by a colon and a blank. Then the message and a new-line.
518  * Input      : format, arguments
519  * Output     : none
520  * Return     : none
521  * Data Used  : none
522  * ------------------------------------------------------------------------- */
523 void
524 P2pdPError(const char *format, ...)
525 {
526 #define MAX_STR_DESC 255
527   char strDesc[MAX_STR_DESC];
528
529 #if !defined REMOVE_LOG_DEBUG
530   char *stringErr = strerror(errno);
531 #endif /* !defined REMOVE_LOG_DEBUG */
532
533   /* Rely on short-circuit boolean evaluation */
534   if (format == NULL || *format == '\0') {
535     //OLSR_DEBUG(LOG_PLUGINS, "%s: %s\n", PLUGIN_NAME, stringErr);
536   } else {
537     va_list arglist;
538
539     va_start(arglist, format);
540     vsnprintf(strDesc, MAX_STR_DESC, format, arglist);
541     va_end(arglist);
542
543     strDesc[MAX_STR_DESC - 1] = '\0';   /* Ensures null termination */
544
545 #if !defined REMOVE_LOG_DEBUG
546     OLSR_DEBUG(LOG_PLUGINS, "%s: %s\n", strDesc, stringErr);
547 #endif /* !defined REMOVE_LOG_DEBUG */
548   }
549 }                               /* P2pdPError */
550
551 /* -------------------------------------------------------------------------
552  * Function   : MainAddressOf
553  * Description: Lookup the main address of a node
554  * Input      : ip - IP address of the node
555  * Output     : none
556  * Return     : The main IP address of the node
557  * Data Used  : none
558  * ------------------------------------------------------------------------- */
559 union olsr_ip_addr *
560 MainAddressOf(union olsr_ip_addr *ip)
561 {
562   union olsr_ip_addr *result;
563
564   /* TODO: mid_lookup_main_addr() is not thread-safe! */
565   result = mid_lookup_main_addr(ip);
566   if (result == NULL) {
567     result = ip;
568   }
569   return result;
570 }                               /* MainAddressOf */
571
572
573 /* -------------------------------------------------------------------------
574  * Function   : InUdpDestPortList
575  * Description: Check whether the specified address and port is in the list of
576  *              configured UDP destination/port entries
577  * Input      : ip_version  - IP version to use for this check
578  *              addr        - address to check for in the list
579  *              port        - port to check for in the list
580  * Output     : none
581  * Return     : true if destination/port combination was found, false otherwise
582  * Data Used  : UdpDestPortList
583  * ------------------------------------------------------------------------- */
584 bool
585 InUdpDestPortList(int ip_version, union olsr_ip_addr *addr, uint16_t port)
586 {
587   struct UdpDestPort *walker;
588
589   for (walker = UdpDestPortList; walker; walker = walker->next) {
590     if (walker->ip_version == ip_version) {
591       if (ip_version == AF_INET) {
592         if (addr->v4.s_addr == walker->address.v4.s_addr &&
593             walker->port == port)
594           return true;  // Found so we can stop here
595       } else /* ip_version == AF_INET6 */ {
596         if ((memcmp(addr->v6.s6_addr,
597                    walker->address.v6.s6_addr,
598                    sizeof(addr->v6.s6_addr)) == 0) &&
599             (walker->port == port))
600           return true;  // Found so we can stop here
601       }
602     }
603   }
604   return false;
605 }
606
607 /* -------------------------------------------------------------------------
608  * Function   : P2pdPacketCaptured
609  * Description: Handle a captured IP packet
610  * Input      : encapsulationUdpData - space for the encapsulation header,
611  *              followed by the captured IP packet
612  *              nBytes - The number of bytes in the data packet
613  * Output     : none
614  * Return     : none
615  * Data Used  : P2pdInterfaces
616  * Notes      : The IP packet is assumed to be captured on a socket of family
617  *              PF_PACKET and type SOCK_DGRAM (cooked).
618  * ------------------------------------------------------------------------- */
619 static void
620 P2pdPacketCaptured(unsigned char *encapsulationUdpData, int nBytes)
621 {
622   union olsr_ip_addr dst;      /* Destination IP address in captured packet */
623   struct ip *ipHeader;         /* The IP header inside the captured IP packet */
624   struct ip6_hdr *ipHeader6;   /* The IP header inside the captured IP packet */
625   struct udphdr *udpHeader;
626   uint8_t * ttl = NULL;
627   u_int16_t destPort;
628
629   if ((encapsulationUdpData[0] & 0xf0) == 0x40) {       //IPV4
630
631     ipHeader = (struct ip *) ARM_NOWARN_ALIGN(encapsulationUdpData);
632
633     dst.v4 = ipHeader->ip_dst;
634
635     if (ipHeader->ip_p != SOL_UDP) {
636       /* Not UDP */
637 #ifdef INCLUDE_DEBUG_OUTPUT
638       OLSR_PRINTF(1,"%s: NON UDP PACKET\n", PLUGIN_NAME_SHORT);
639 #endif /* INCLUDE_DEBUG_OUTPUT */
640       return;                   /* for */
641     }
642
643     // If we're dealing with a fragment we bail out here since there's no valid
644     // UDP header in this message
645     if (IsIpv4Fragment(ipHeader)) {
646 #ifdef INCLUDE_DEBUG_OUTPUT
647       OLSR_PRINTF(1, "%s: Is IPv4 fragment\n", PLUGIN_NAME_SHORT);
648 #endif /* INCLUDE_DEBUG_OUTPUT */
649       return;
650     }
651
652     if (check_and_mark_recent_packet(encapsulationUdpData, nBytes))
653       return;
654
655     udpHeader = (struct udphdr *) ARM_NOWARN_ALIGN((encapsulationUdpData +
656                                   GetIpHeaderLength(encapsulationUdpData)));
657     destPort = ntohs(udpHeader->dest);
658
659     if (!InUdpDestPortList(AF_INET, &dst, destPort)) {
660 #ifdef INCLUDE_DEBUG_OUTPUT
661       char tmp[32];
662       OLSR_PRINTF(1, "%s: Not in dest/port list: %s:%d\n", PLUGIN_NAME_SHORT,
663                   get_ipv4_str(dst.v4.s_addr, tmp, sizeof(tmp)), destPort);
664 #endif /* INCLUDE_DEBUG_OUTPUT */
665        return;
666     }
667
668     ttl = &ipHeader->ip_ttl;
669   }                            //END IPV4
670   else if ((encapsulationUdpData[0] & 0xf0) == 0x60) {  //IPv6
671
672     ipHeader6 = (struct ip6_hdr *) ARM_NOWARN_ALIGN(encapsulationUdpData);
673
674     memcpy(&dst.v6, &ipHeader6->ip6_dst, sizeof(struct in6_addr));
675
676     if (ipHeader6->ip6_dst.s6_addr[0] == 0xff)  //Multicast
677     {
678       //Continue
679     } else {
680       return;                   //not multicast
681     }
682     if (ipHeader6->ip6_nxt != SOL_UDP) {
683       /* Not UDP */
684       //OLSR_PRINTF(1,"%s: NON UDP PACKET\n", PLUGIN_NAME_SHORT);
685       return;                   /* for */
686     }
687
688     // Check whether this is a IPv6 fragment
689     if (IsIpv6Fragment(ipHeader6)) {
690 #ifdef INCLUDE_DEBUG_OUTPUT
691       OLSR_PRINTF(1, "%s: Is IPv6 fragment\n", PLUGIN_NAME_SHORT);
692 #endif /* INCLUDE_DEBUG_OUTPUT */
693       return;
694     }
695
696     if (check_and_mark_recent_packet(encapsulationUdpData, nBytes))
697       return;
698
699     udpHeader = (struct udphdr *) ARM_NOWARN_ALIGN((encapsulationUdpData + 40));
700     destPort = ntohs(udpHeader->dest);
701
702     if (!InUdpDestPortList(AF_INET6, &dst, destPort)) {
703 #ifdef INCLUDE_DEBUG_OUTPUT
704       char tmp[64];
705       OLSR_PRINTF(1, "%s: Not in dest/port list: %s:%d\n", PLUGIN_NAME_SHORT,
706                   get_ipv6_str(dst.v6.s6_addr, tmp, sizeof(tmp)), destPort);
707 #endif /* INCLUDE_DEBUG_OUTPUT */
708       return;
709     }
710
711     ttl = &ipHeader6->ip6_ctlun.ip6_un1.ip6_un1_hlim;
712   }                             //END IPV6
713   else {
714     return;                     //Is not IP packet
715   }
716
717   if (P2pdUseTtlDecrement) {
718     assert(ttl);
719     if (!*ttl) {
720       return;
721     }
722     *ttl -= 1;
723     if (!*ttl) {
724       return;
725     }
726   }
727
728   // send the packet to OLSR forward mechanism
729   olsr_p2pd_gen(encapsulationUdpData, nBytes);
730 }                               /* P2pdPacketCaptured */
731
732
733 /* -------------------------------------------------------------------------
734  * Function   : DoP2pd
735  * Description: This function is registered with the OLSR scheduler and called
736  *              when something is captured
737  * Input      : none
738  * Output     : none
739  * Return     : none
740  * Data Used  :
741  * ------------------------------------------------------------------------- */
742 void
743 DoP2pd(int skfd,
744        void *data __attribute__ ((unused)),
745        unsigned int flags __attribute__ ((unused)))
746 {
747   unsigned char rxBuffer[P2PD_BUFFER_SIZE];
748   if (skfd >= 0) {
749     struct sockaddr_ll pktAddr;
750     socklen_t addrLen = sizeof(pktAddr);
751     int nBytes;
752     unsigned char *ipPacket;
753
754     /* Receive the captured Ethernet frame, leaving space for the BMF
755      * encapsulation header */
756     ipPacket = GetIpPacket(rxBuffer);
757     nBytes = recvfrom(skfd, ipPacket, P2PD_BUFFER_SIZE,
758                       0, (struct sockaddr *)&pktAddr, &addrLen);
759 #ifdef INCLUDE_DEBUG_OUTPUT
760     OLSR_PRINTF(1, "%s: Received %d bytes\n", PLUGIN_NAME_SHORT, nBytes);
761 #endif /* INCLUDE_DEBUG_OUTPUT */
762
763     if (nBytes < 0) {
764
765       return;                   /* for */
766     }
767
768     /* if (nBytes < 0) */
769     /* Check if the number of received bytes is large enough for an IP
770      * packet which contains at least a minimum-size IP header.
771      * Note: There is an apparent bug in the packet socket implementation in
772      * combination with VLAN interfaces. On a VLAN interface, the value returned
773      * by 'recvfrom' may (but need not) be 4 (bytes) larger than the value
774      * returned on a non-VLAN interface, for the same ethernet frame. */
775     if (nBytes < (int)sizeof(struct ip)) {
776       ////OLSR_PRINTF(
777       //              1,
778       //              "%s: captured frame too short (%d bytes) on \"%s\"\n",
779       //              PLUGIN_NAME_SHORT,
780       //              nBytes,
781       //              walker->ifName);
782
783       return;                   /* for */
784     }
785
786     if (pktAddr.sll_pkttype == PACKET_OUTGOING ||
787         pktAddr.sll_pkttype == PACKET_MULTICAST ||
788         pktAddr.sll_pkttype == PACKET_BROADCAST) {
789 #ifdef INCLUDE_DEBUG_OUTPUT
790       OLSR_PRINTF(1, "%s: Multicast or broadcast packet was captured.\n",
791                   PLUGIN_NAME_SHORT);
792       dump_packet(ipPacket, nBytes);
793 #endif /* INCLUDE_DEBUG_OUTPUT */
794       /* A multicast or broadcast packet was captured */
795       P2pdPacketCaptured(ipPacket, nBytes);
796
797     }                           /* if (pktAddr.sll_pkttype == ...) */
798   }                             /* if (skfd >= 0 && (FD_ISSET...)) */
799 }                               /* DoP2pd */
800
801 /* -------------------------------------------------------------------------
802  * Function   : InitP2pd
803  * Description: Initialize the P2pd plugin
804  * Input      : skipThisInterface - pointer to interface to skip
805  * Output     : none
806  * Return     : Always 0
807  * Data Used  : none
808  * ------------------------------------------------------------------------- */
809 int
810 InitP2pd(struct interface *skipThisIntf)
811 {
812   if (P2pdUseHash) {
813     // Initialize hash table for hash based duplicate IP packet check
814     InitPacketHistory();
815   }
816
817   //Tells OLSR to launch olsr_parser when the packets for this plugin arrive
818   //olsr_parser_add_function(&olsr_parser, PARSER_TYPE,1);
819   olsr_parser_add_function(&olsr_parser, PARSER_TYPE);
820
821   //Creates captures sockets and register them to the OLSR scheduler
822   CreateNonOlsrNetworkInterfaces(skipThisIntf);
823
824   return 0;
825 }                               /* InitP2pd */
826
827 /* -------------------------------------------------------------------------
828  * Function   : CloseP2pd
829  * Description: Close the P2pd plugin and clean up
830  * Input      : none
831  * Output     : none
832  * Return     : none
833  * Data Used  :
834  * ------------------------------------------------------------------------- */
835 void
836 CloseP2pd(void)
837 {
838   CloseNonOlsrNetworkInterfaces();
839 }
840
841 /* -------------------------------------------------------------------------
842  * Function   : SetP2pdTtl
843  * Description: Set the TTL for message from this plugin
844  * Input      : value - parameter value to evaluate
845  * Output     : none
846  * Return     : Always 0
847  * Data Used  : P2pdTtl
848  * ------------------------------------------------------------------------- */
849 int
850 SetP2pdTtl(const char *value,
851            void *data __attribute__ ((unused)),
852            set_plugin_parameter_addon addon __attribute__ ((unused)))
853 {
854   assert(value != NULL);
855   P2pdTtl = atoi(value);
856
857   return 0;
858 }
859
860 /* -------------------------------------------------------------------------
861  * Function   : SetP2pdUseHashFilter
862  * Description: Set the Hash filter flag for this plug-in
863  * Input      : value - parameter value to evaluate
864  *              data  - data associated with this parameter (unused in this app)
865  *              addon - additional parameter data
866  * Output     : none
867  * Return     : Always 0
868  * Data Used  : P2pdUseHash
869  * ------------------------------------------------------------------------- */
870 int
871 SetP2pdUseHashFilter(const char *value,
872                      void *data __attribute__ ((unused)),
873                      set_plugin_parameter_addon addon __attribute__ ((unused)))
874 {
875   assert(value != NULL);
876   P2pdUseHash = atoi(value);
877   
878   return 0;
879 }
880
881 /* -------------------------------------------------------------------------
882  * Function   : SetP2pdUseTtlDecrement
883  * Description: Set the TTL decrement lag for this plug-in
884  * Input      : value - parameter value to evaluate
885  *              data  - data associated with this parameter (unused in this app)
886  *              addon - additional parameter data
887  * Output     : none
888  * Return     : Always 0
889  * Data Used  : P2pdUseTtlDecrement
890  * ------------------------------------------------------------------------- */
891 int
892 SetP2pdUseTtlDecrement(const char *value,
893                      void *data __attribute__ ((unused)),
894                      set_plugin_parameter_addon addon __attribute__ ((unused)))
895 {
896   assert(value != NULL);
897   P2pdUseTtlDecrement = atoi(value);
898
899   return 0;
900 }
901
902 /* -------------------------------------------------------------------------
903  * Function   : AddUdpDestPort
904  * Description: Set the UDP destination/port combination as an entry in the
905  *              UdpDestPortList
906  * Input      : value - parameter value to evaluate
907  * Output     : none
908  * Return     : -1 on error condition, 0 if all is ok
909  * Data Used  : UdpDestPortList
910  * ------------------------------------------------------------------------- */
911 int
912 AddUdpDestPort(const char *value,
913                void *data __attribute__ ((unused)),
914                set_plugin_parameter_addon addon __attribute__ ((unused)))
915 {
916   char destAddr[INET6_ADDRSTRLEN];
917   uint16_t destPort;
918   int num;
919   struct UdpDestPort *    new;
920   struct sockaddr_in      addr4;
921   struct sockaddr_in6     addr6;
922   int                     ip_version    = AF_INET;
923   int                     res;
924
925   assert(value != NULL);
926
927   // Retrieve the data from the argument string passed
928   memset(destAddr, 0, sizeof(destAddr));
929   num = sscanf(value, "%45s %hd", destAddr, &destPort);
930   if (num != 2) {
931     OLSR_PRINTF(1, "%s: Invalid argument for \"UdpDestPort\"",
932                 PLUGIN_NAME_SHORT);
933     return -1;
934   }
935
936   // Check whether we're dealing with an IPv4 or IPv6 address
937   // When the string contains a ':' we can assume we're dealing with IPv6
938   if (strchr(destAddr, (int)':')) {
939     ip_version = AF_INET6;
940   }
941
942   // Check whether the specified address was either IPv4 multicast,
943   // IPv4 broadcast or IPv6 multicast.
944
945   switch (ip_version) {
946   case AF_INET6:
947     res = inet_pton(AF_INET6, destAddr, &addr6.sin6_addr);
948     if (addr6.sin6_addr.s6_addr[0] != 0xFF) {
949       OLSR_PRINTF(1,"WARNING: IPv6 address must be multicast... ");
950       return -1;
951     }
952     break;
953   default:
954     res = inet_pton(AF_INET, destAddr, &addr4.sin_addr);
955     if (!is_broadcast(addr4) && !is_multicast(addr4)) {
956       OLSR_PRINTF(1,"WARNING: IPv4 address must be multicast or broadcast... ");
957     }
958     break;
959   }
960   // Determine whether it is a valid IP address
961   if (res == 0) {
962     OLSR_PRINTF(1, "Invalid address specified for \"UdpDestPort\"");
963     return -1;
964   }
965
966   // Create a new entry and link it into the chain
967   new = calloc(1, sizeof(struct UdpDestPort));
968   if (new == NULL) {
969     OLSR_PRINTF(1, "%s: Out of memory", PLUGIN_NAME_SHORT);
970     return -1;
971   }
972
973   new->ip_version = ip_version;
974   switch (ip_version) {
975   case AF_INET6:
976     memcpy(&new->address.v6.s6_addr,
977            &addr6.sin6_addr.s6_addr,
978            sizeof(addr6.sin6_addr.s6_addr));
979     break;
980   default:
981     new->address.v4.s_addr = addr4.sin_addr.s_addr;
982     break;
983   }
984   new->port = destPort;
985   new->next = UdpDestPortList;
986   UdpDestPortList = new;
987
988   // And then we're done
989   return 0;
990 }
991
992 /* -------------------------------------------------------------------------
993  * Function   : get_ipv4_str
994  * Description: Convert the specified address to an IPv4 compatible string
995  * Input      : address - IPv4 address to convert to string
996  *              s       - string buffer to contain the resulting string
997  *              maxlen  - maximum length of the string buffer
998  * Output     : none
999  * Return     : Pointer to the string buffer containing the result
1000  * Data Used  : none
1001  * ------------------------------------------------------------------------- */
1002 char *
1003 get_ipv4_str(uint32_t address, char *s, size_t maxlen)
1004 {
1005   struct sockaddr_in v4;
1006
1007   v4.sin_addr.s_addr = address;
1008   inet_ntop(AF_INET, &v4.sin_addr, s, maxlen);
1009
1010   return s;
1011 }
1012
1013 /* -------------------------------------------------------------------------
1014  * Function   : get_ipv6_str
1015  * Description: Convert the specified address to an IPv4 compatible string
1016  * Input      : address - IPv6 address to convert to string
1017  *              s       - string buffer to contain the resulting string
1018  *              maxlen  - maximum length of the string buffer
1019  * Output     : none
1020  * Return     : Pointer to the string buffer containing the result
1021  * Data Used  : none
1022  * ------------------------------------------------------------------------- */
1023 char *
1024 get_ipv6_str(unsigned char* address, char *s, size_t maxlen)
1025 {
1026   struct sockaddr_in6 v6;
1027
1028   memcpy(v6.sin6_addr.s6_addr, address, sizeof(v6.sin6_addr.s6_addr));
1029   inet_ntop(AF_INET6, &v6.sin6_addr, s, maxlen);
1030
1031   return s;
1032 }
1033
1034 /* -------------------------------------------------------------------------
1035  * Function   : is_broadcast
1036  * Description: Check whether the address represents a broadcast address
1037  * Input      : addr - IPv4 address to check
1038  * Output     : none
1039  * Return     : true if broadcast address, false otherwise
1040  * Data Used  : none
1041  * ------------------------------------------------------------------------- */
1042 bool
1043 is_broadcast(const struct sockaddr_in addr)
1044 {
1045   if (addr.sin_addr.s_addr == 0xFFFFFFFF)
1046     return true;
1047
1048   return false;
1049 }
1050
1051 /* -------------------------------------------------------------------------
1052  * Function   : is_multicast
1053  * Description: Check whether the address represents a multicast address
1054  * Input      : addr - IPv4 address to check
1055  * Output     : none
1056  * Return     : true if broadcast address, false otherwise
1057  * Data Used  : none
1058  * ------------------------------------------------------------------------- */
1059 bool
1060 is_multicast(const struct sockaddr_in addr)
1061 {
1062   if ((htonl(addr.sin_addr.s_addr) & 0xE0000000) == 0xE0000000)
1063     return true;
1064
1065   return false;
1066 }
1067
1068 #ifdef INCLUDE_DEBUG_OUTPUT
1069 /* -------------------------------------------------------------------------
1070  * Function   : dump_packet
1071  * Description: Dump the specified data as hex output
1072  * Input      : packet - packet to dump to output
1073  *              length - length of the data in the packet
1074  * Output     : none
1075  * Return     : nothing
1076  * Data Used  : none
1077  * ------------------------------------------------------------------------- */
1078 void
1079 dump_packet(unsigned char* packet, int length)
1080 {
1081   int idx;
1082
1083   OLSR_PRINTF(1, "%s: ", PLUGIN_NAME_SHORT);
1084   for (idx = 0; idx < length; idx++) {
1085     if (idx > 0 && ((idx % 16) == 0))
1086       OLSR_PRINTF(1, "\n%s: ", PLUGIN_NAME_SHORT);
1087     OLSR_PRINTF(1, "%2.2X ", packet[idx]);
1088   }
1089   OLSR_PRINTF(1, "\n");
1090 }
1091 #endif /* INCLUDE_DEBUG_OUTPUT */
1092
1093 /* -------------------------------------------------------------------------
1094  * Function   : check_and_mark_recent_packet
1095  * Description: Wrapper function for the Hash based duplicate check
1096  * Input      : data - pointer to a packet of data to be checked
1097  * Output     : none
1098  * Return     : true if duplicate packet, false otherwise
1099  * Data Used  : P2pdUseHash
1100  * ------------------------------------------------------------------------- */
1101 bool
1102 check_and_mark_recent_packet(unsigned char *data,
1103                              int len __attribute__ ((unused)))
1104 {
1105   unsigned char * ipPacket;
1106   uint16_t ipPacketLen;
1107   uint32_t crc32;
1108
1109   /* If we don't use this filter bail out here */
1110   if (!P2pdUseHash)
1111     return false;
1112     
1113   /* Clean up the hash table each time before we check it */
1114   PrunePacketHistory(NULL);
1115
1116   /* Check for duplicate IP packets now based on a hash */
1117   ipPacket = GetIpPacket(data);
1118   ipPacketLen = GetIpTotalLength(ipPacket);
1119
1120   /* Calculate packet fingerprint */
1121   crc32 = PacketCrc32(ipPacket, ipPacketLen);
1122
1123   /* Check if this packet was seen recently */
1124   if (CheckAndMarkRecentPacket(crc32))
1125   {
1126     OLSR_PRINTF(
1127       8,
1128       "%s: --> discarding: packet is duplicate\n",
1129       PLUGIN_NAME_SHORT);
1130     return true;
1131   }
1132
1133   return false;
1134 }