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