Rename 'struct interface' to 'struct interface_olsr'
[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_olsr *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_olsr *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 for checksum calculation.
609  * From the RFC, the checksum algorithm is:
610  *   "The checksum field is the 16 bit one's complement of the one's
611  *   complement sum of all 16 bit words in the header. For purposes of
612  *   computing the checksum, the value of the checksum field is zero."
613  *
614  * For example, consider Hex 4500003044224000800600008c7c19acae241e2b (20 bytes IP header):
615  * - Step 1) 4500 + 0030 + 4422 + 4000 + 8006 + 0000 + 8c7c + 19ac + ae24 + 1e2b = 0002`BBCF (16-bit sum)
616  * - Step 2) 0002 + BBCF = BBD1 = 1011101111010001 (1's complement 16-bit sum)
617  * - Step 3) ~BBD1 = 0100010000101110 = 442E (1's complement of 1's complement 16-bit sum)
618  */
619 static void recomputeIPv4HeaderChecksum(struct ip *header) {
620   uint32_t sum;
621   uint32_t nwords;
622   u_short *headerWords;
623
624   if (!header) {
625     return;
626   }
627
628   header->ip_sum = 0;
629   nwords = header->ip_hl << 1;
630   headerWords = (u_short *) header;
631
632   /* step 1 */
633   for (sum = 0; nwords > 0; nwords--) {
634     sum += ntohs(*headerWords);
635     headerWords++;
636   }
637
638   /* step 2 */
639   sum = (sum >> 16) + (sum & 0xffff);
640
641   /* step 3 */
642   sum = ~sum & 0xffff;
643
644   header->ip_sum = htons((u_short)sum);
645 }
646
647 /* -------------------------------------------------------------------------
648  * Function   : P2pdPacketCaptured
649  * Description: Handle a captured IP packet
650  * Input      : encapsulationUdpData - space for the encapsulation header,
651  *              followed by the captured IP packet
652  *              nBytes - The number of bytes in the data packet
653  * Output     : none
654  * Return     : none
655  * Data Used  : P2pdInterfaces
656  * Notes      : The IP packet is assumed to be captured on a socket of family
657  *              PF_PACKET and type SOCK_DGRAM (cooked).
658  * ------------------------------------------------------------------------- */
659 static void
660 P2pdPacketCaptured(unsigned char *encapsulationUdpData, int nBytes)
661 {
662   union olsr_ip_addr dst;      /* Destination IP address in captured packet */
663   struct ip *ipHeader = NULL;  /* The IP header inside the captured IP packet */
664   struct ip6_hdr *ipHeader6;   /* The IP header inside the captured IP packet */
665   struct udphdr *udpHeader;
666   uint8_t * ttl = NULL;
667   int recomputeChecksum = 0;
668   u_int16_t destPort;
669
670   if ((encapsulationUdpData[0] & 0xf0) == 0x40) {       //IPV4
671
672     ipHeader = (struct ip *) ARM_NOWARN_ALIGN(encapsulationUdpData);
673
674     dst.v4 = ipHeader->ip_dst;
675
676     if (ipHeader->ip_p != SOL_UDP) {
677       /* Not UDP */
678 #ifdef INCLUDE_DEBUG_OUTPUT
679       OLSR_PRINTF(1,"%s: NON UDP PACKET\n", PLUGIN_NAME_SHORT);
680 #endif /* INCLUDE_DEBUG_OUTPUT */
681       return;                   /* for */
682     }
683
684     // If we're dealing with a fragment we bail out here since there's no valid
685     // UDP header in this message
686     if (IsIpv4Fragment(ipHeader)) {
687 #ifdef INCLUDE_DEBUG_OUTPUT
688       OLSR_PRINTF(1, "%s: Is IPv4 fragment\n", PLUGIN_NAME_SHORT);
689 #endif /* INCLUDE_DEBUG_OUTPUT */
690       return;
691     }
692
693     if (check_and_mark_recent_packet(encapsulationUdpData, nBytes))
694       return;
695
696     udpHeader = (struct udphdr *) ARM_NOWARN_ALIGN((encapsulationUdpData +
697                                   GetIpHeaderLength(encapsulationUdpData)));
698     destPort = ntohs(udpHeader->dest);
699
700     if (!InUdpDestPortList(AF_INET, &dst, destPort)) {
701 #ifdef INCLUDE_DEBUG_OUTPUT
702       char tmp[32];
703       OLSR_PRINTF(1, "%s: Not in dest/port list: %s:%d\n", PLUGIN_NAME_SHORT,
704                   get_ipv4_str(dst.v4.s_addr, tmp, sizeof(tmp)), destPort);
705 #endif /* INCLUDE_DEBUG_OUTPUT */
706        return;
707     }
708
709     ttl = &ipHeader->ip_ttl;
710     recomputeChecksum = 1;
711   }                            //END IPV4
712   else if ((encapsulationUdpData[0] & 0xf0) == 0x60) {  //IPv6
713
714     ipHeader6 = (struct ip6_hdr *) ARM_NOWARN_ALIGN(encapsulationUdpData);
715
716     memcpy(&dst.v6, &ipHeader6->ip6_dst, sizeof(struct in6_addr));
717
718     if (ipHeader6->ip6_dst.s6_addr[0] == 0xff)  //Multicast
719     {
720       //Continue
721     } else {
722       return;                   //not multicast
723     }
724     if (ipHeader6->ip6_nxt != SOL_UDP) {
725       /* Not UDP */
726       //OLSR_PRINTF(1,"%s: NON UDP PACKET\n", PLUGIN_NAME_SHORT);
727       return;                   /* for */
728     }
729
730     // Check whether this is a IPv6 fragment
731     if (IsIpv6Fragment(ipHeader6)) {
732 #ifdef INCLUDE_DEBUG_OUTPUT
733       OLSR_PRINTF(1, "%s: Is IPv6 fragment\n", PLUGIN_NAME_SHORT);
734 #endif /* INCLUDE_DEBUG_OUTPUT */
735       return;
736     }
737
738     if (check_and_mark_recent_packet(encapsulationUdpData, nBytes))
739       return;
740
741     udpHeader = (struct udphdr *) ARM_NOWARN_ALIGN((encapsulationUdpData + 40));
742     destPort = ntohs(udpHeader->dest);
743
744     if (!InUdpDestPortList(AF_INET6, &dst, destPort)) {
745 #ifdef INCLUDE_DEBUG_OUTPUT
746       char tmp[64];
747       OLSR_PRINTF(1, "%s: Not in dest/port list: %s:%d\n", PLUGIN_NAME_SHORT,
748                   get_ipv6_str(dst.v6.s6_addr, tmp, sizeof(tmp)), destPort);
749 #endif /* INCLUDE_DEBUG_OUTPUT */
750       return;
751     }
752
753     ttl = &ipHeader6->ip6_ctlun.ip6_un1.ip6_un1_hlim;
754     recomputeChecksum = 0;
755   }                             //END IPV6
756   else {
757     return;                     //Is not IP packet
758   }
759
760   if (P2pdUseTtlDecrement) {
761     assert(ttl);
762     if (!*ttl) {
763       return;
764     }
765     *ttl -= 1;
766     if (!*ttl) {
767       return;
768     }
769
770     if (recomputeChecksum) {
771       recomputeIPv4HeaderChecksum(ipHeader);
772     }
773   }
774
775   // send the packet to OLSR forward mechanism
776   olsr_p2pd_gen(encapsulationUdpData, nBytes);
777 }                               /* P2pdPacketCaptured */
778
779
780 /* -------------------------------------------------------------------------
781  * Function   : DoP2pd
782  * Description: This function is registered with the OLSR scheduler and called
783  *              when something is captured
784  * Input      : none
785  * Output     : none
786  * Return     : none
787  * Data Used  :
788  * ------------------------------------------------------------------------- */
789 void
790 DoP2pd(int skfd,
791        void *data __attribute__ ((unused)),
792        unsigned int flags __attribute__ ((unused)))
793 {
794   unsigned char rxBuffer[P2PD_BUFFER_SIZE];
795   if (skfd >= 0) {
796     struct sockaddr_ll pktAddr;
797     socklen_t addrLen = sizeof(pktAddr);
798     int nBytes;
799     unsigned char *ipPacket;
800
801     /* Receive the captured Ethernet frame, leaving space for the BMF
802      * encapsulation header */
803     ipPacket = GetIpPacket(rxBuffer);
804     nBytes = recvfrom(skfd, ipPacket, P2PD_BUFFER_SIZE,
805                       0, (struct sockaddr *)&pktAddr, &addrLen);
806 #ifdef INCLUDE_DEBUG_OUTPUT
807     OLSR_PRINTF(1, "%s: Received %d bytes\n", PLUGIN_NAME_SHORT, nBytes);
808 #endif /* INCLUDE_DEBUG_OUTPUT */
809
810     if (nBytes < 0) {
811
812       return;                   /* for */
813     }
814
815     /* if (nBytes < 0) */
816     /* Check if the number of received bytes is large enough for an IP
817      * packet which contains at least a minimum-size IP header.
818      * Note: There is an apparent bug in the packet socket implementation in
819      * combination with VLAN interfaces. On a VLAN interface, the value returned
820      * by 'recvfrom' may (but need not) be 4 (bytes) larger than the value
821      * returned on a non-VLAN interface, for the same ethernet frame. */
822     if (nBytes < (int)sizeof(struct ip)) {
823       ////OLSR_PRINTF(
824       //              1,
825       //              "%s: captured frame too short (%d bytes) on \"%s\"\n",
826       //              PLUGIN_NAME_SHORT,
827       //              nBytes,
828       //              walker->ifName);
829
830       return;                   /* for */
831     }
832
833     if (pktAddr.sll_pkttype == PACKET_OUTGOING ||
834         pktAddr.sll_pkttype == PACKET_MULTICAST ||
835         pktAddr.sll_pkttype == PACKET_BROADCAST) {
836 #ifdef INCLUDE_DEBUG_OUTPUT
837       OLSR_PRINTF(1, "%s: Multicast or broadcast packet was captured.\n",
838                   PLUGIN_NAME_SHORT);
839       dump_packet(ipPacket, nBytes);
840 #endif /* INCLUDE_DEBUG_OUTPUT */
841       /* A multicast or broadcast packet was captured */
842       P2pdPacketCaptured(ipPacket, nBytes);
843
844     }                           /* if (pktAddr.sll_pkttype == ...) */
845   }                             /* if (skfd >= 0 && (FD_ISSET...)) */
846 }                               /* DoP2pd */
847
848 /* -------------------------------------------------------------------------
849  * Function   : InitP2pd
850  * Description: Initialize the P2pd plugin
851  * Input      : skipThisInterface - pointer to interface to skip
852  * Output     : none
853  * Return     : Always 0
854  * Data Used  : none
855  * ------------------------------------------------------------------------- */
856 int
857 InitP2pd(struct interface_olsr *skipThisIntf)
858 {
859   if (P2pdUseHash) {
860     // Initialize hash table for hash based duplicate IP packet check
861     InitPacketHistory();
862   }
863
864   //Tells OLSR to launch olsr_parser when the packets for this plugin arrive
865   //olsr_parser_add_function(&olsr_parser, PARSER_TYPE,1);
866   olsr_parser_add_function(&olsr_parser, PARSER_TYPE);
867
868   //Creates captures sockets and register them to the OLSR scheduler
869   CreateNonOlsrNetworkInterfaces(skipThisIntf);
870
871   return 0;
872 }                               /* InitP2pd */
873
874 /* -------------------------------------------------------------------------
875  * Function   : CloseP2pd
876  * Description: Close the P2pd plugin and clean up
877  * Input      : none
878  * Output     : none
879  * Return     : none
880  * Data Used  :
881  * ------------------------------------------------------------------------- */
882 void
883 CloseP2pd(void)
884 {
885   CloseNonOlsrNetworkInterfaces();
886 }
887
888 /* -------------------------------------------------------------------------
889  * Function   : SetP2pdTtl
890  * Description: Set the TTL for message from this plugin
891  * Input      : value - parameter value to evaluate
892  * Output     : none
893  * Return     : Always 0
894  * Data Used  : P2pdTtl
895  * ------------------------------------------------------------------------- */
896 int
897 SetP2pdTtl(const char *value,
898            void *data __attribute__ ((unused)),
899            set_plugin_parameter_addon addon __attribute__ ((unused)))
900 {
901   assert(value != NULL);
902   P2pdTtl = atoi(value);
903
904   return 0;
905 }
906
907 /* -------------------------------------------------------------------------
908  * Function   : SetP2pdUseHashFilter
909  * Description: Set the Hash filter flag for this plug-in
910  * Input      : value - parameter value to evaluate
911  *              data  - data associated with this parameter (unused in this app)
912  *              addon - additional parameter data
913  * Output     : none
914  * Return     : Always 0
915  * Data Used  : P2pdUseHash
916  * ------------------------------------------------------------------------- */
917 int
918 SetP2pdUseHashFilter(const char *value,
919                      void *data __attribute__ ((unused)),
920                      set_plugin_parameter_addon addon __attribute__ ((unused)))
921 {
922   assert(value != NULL);
923   P2pdUseHash = atoi(value);
924   
925   return 0;
926 }
927
928 /* -------------------------------------------------------------------------
929  * Function   : SetP2pdUseTtlDecrement
930  * Description: Set the TTL decrement lag for this plug-in
931  * Input      : value - parameter value to evaluate
932  *              data  - data associated with this parameter (unused in this app)
933  *              addon - additional parameter data
934  * Output     : none
935  * Return     : Always 0
936  * Data Used  : P2pdUseTtlDecrement
937  * ------------------------------------------------------------------------- */
938 int
939 SetP2pdUseTtlDecrement(const char *value,
940                      void *data __attribute__ ((unused)),
941                      set_plugin_parameter_addon addon __attribute__ ((unused)))
942 {
943   assert(value != NULL);
944   P2pdUseTtlDecrement = atoi(value);
945
946   return 0;
947 }
948
949 /* -------------------------------------------------------------------------
950  * Function   : AddUdpDestPort
951  * Description: Set the UDP destination/port combination as an entry in the
952  *              UdpDestPortList
953  * Input      : value - parameter value to evaluate
954  * Output     : none
955  * Return     : -1 on error condition, 0 if all is ok
956  * Data Used  : UdpDestPortList
957  * ------------------------------------------------------------------------- */
958 int
959 AddUdpDestPort(const char *value,
960                void *data __attribute__ ((unused)),
961                set_plugin_parameter_addon addon __attribute__ ((unused)))
962 {
963   char destAddr[INET6_ADDRSTRLEN];
964   uint16_t destPort;
965   int num;
966   struct UdpDestPort *    new;
967   struct sockaddr_in      addr4;
968   struct sockaddr_in6     addr6;
969   int                     ip_version    = AF_INET;
970   int                     res;
971
972   assert(value != NULL);
973
974   // Retrieve the data from the argument string passed
975   memset(destAddr, 0, sizeof(destAddr));
976   num = sscanf(value, "%45s %hd", destAddr, &destPort);
977   if (num != 2) {
978     OLSR_PRINTF(1, "%s: Invalid argument for \"UdpDestPort\"",
979                 PLUGIN_NAME_SHORT);
980     return -1;
981   }
982
983   // Check whether we're dealing with an IPv4 or IPv6 address
984   // When the string contains a ':' we can assume we're dealing with IPv6
985   if (strchr(destAddr, (int)':')) {
986     ip_version = AF_INET6;
987   }
988
989   // Check whether the specified address was either IPv4 multicast,
990   // IPv4 broadcast or IPv6 multicast.
991
992   switch (ip_version) {
993   case AF_INET6:
994     res = inet_pton(AF_INET6, destAddr, &addr6.sin6_addr);
995     if (addr6.sin6_addr.s6_addr[0] != 0xFF) {
996       OLSR_PRINTF(1,"WARNING: IPv6 address must be multicast... ");
997       return -1;
998     }
999     break;
1000   default:
1001     res = inet_pton(AF_INET, destAddr, &addr4.sin_addr);
1002     if (!is_broadcast(addr4) && !is_multicast(addr4)) {
1003       OLSR_PRINTF(1,"WARNING: IPv4 address must be multicast or broadcast... ");
1004     }
1005     break;
1006   }
1007   // Determine whether it is a valid IP address
1008   if (res == 0) {
1009     OLSR_PRINTF(1, "Invalid address specified for \"UdpDestPort\"");
1010     return -1;
1011   }
1012
1013   // Create a new entry and link it into the chain
1014   new = calloc(1, sizeof(struct UdpDestPort));
1015   if (new == NULL) {
1016     OLSR_PRINTF(1, "%s: Out of memory", PLUGIN_NAME_SHORT);
1017     return -1;
1018   }
1019
1020   new->ip_version = ip_version;
1021   switch (ip_version) {
1022   case AF_INET6:
1023     memcpy(&new->address.v6.s6_addr,
1024            &addr6.sin6_addr.s6_addr,
1025            sizeof(addr6.sin6_addr.s6_addr));
1026     break;
1027   default:
1028     new->address.v4.s_addr = addr4.sin_addr.s_addr;
1029     break;
1030   }
1031   new->port = destPort;
1032   new->next = UdpDestPortList;
1033   UdpDestPortList = new;
1034
1035   // And then we're done
1036   return 0;
1037 }
1038
1039 /* -------------------------------------------------------------------------
1040  * Function   : get_ipv4_str
1041  * Description: Convert the specified address to an IPv4 compatible string
1042  * Input      : address - IPv4 address to convert to string
1043  *              s       - string buffer to contain the resulting string
1044  *              maxlen  - maximum length of the string buffer
1045  * Output     : none
1046  * Return     : Pointer to the string buffer containing the result
1047  * Data Used  : none
1048  * ------------------------------------------------------------------------- */
1049 char *
1050 get_ipv4_str(uint32_t address, char *s, size_t maxlen)
1051 {
1052   struct sockaddr_in v4;
1053
1054   v4.sin_addr.s_addr = address;
1055   inet_ntop(AF_INET, &v4.sin_addr, s, maxlen);
1056
1057   return s;
1058 }
1059
1060 /* -------------------------------------------------------------------------
1061  * Function   : get_ipv6_str
1062  * Description: Convert the specified address to an IPv4 compatible string
1063  * Input      : address - IPv6 address to convert to string
1064  *              s       - string buffer to contain the resulting string
1065  *              maxlen  - maximum length of the string buffer
1066  * Output     : none
1067  * Return     : Pointer to the string buffer containing the result
1068  * Data Used  : none
1069  * ------------------------------------------------------------------------- */
1070 char *
1071 get_ipv6_str(unsigned char* address, char *s, size_t maxlen)
1072 {
1073   struct sockaddr_in6 v6;
1074
1075   memcpy(v6.sin6_addr.s6_addr, address, sizeof(v6.sin6_addr.s6_addr));
1076   inet_ntop(AF_INET6, &v6.sin6_addr, s, maxlen);
1077
1078   return s;
1079 }
1080
1081 /* -------------------------------------------------------------------------
1082  * Function   : is_broadcast
1083  * Description: Check whether the address represents a broadcast address
1084  * Input      : addr - IPv4 address to check
1085  * Output     : none
1086  * Return     : true if broadcast address, false otherwise
1087  * Data Used  : none
1088  * ------------------------------------------------------------------------- */
1089 bool
1090 is_broadcast(const struct sockaddr_in addr)
1091 {
1092   if (addr.sin_addr.s_addr == 0xFFFFFFFF)
1093     return true;
1094
1095   return false;
1096 }
1097
1098 /* -------------------------------------------------------------------------
1099  * Function   : is_multicast
1100  * Description: Check whether the address represents a multicast address
1101  * Input      : addr - IPv4 address to check
1102  * Output     : none
1103  * Return     : true if broadcast address, false otherwise
1104  * Data Used  : none
1105  * ------------------------------------------------------------------------- */
1106 bool
1107 is_multicast(const struct sockaddr_in addr)
1108 {
1109   if ((htonl(addr.sin_addr.s_addr) & 0xE0000000) == 0xE0000000)
1110     return true;
1111
1112   return false;
1113 }
1114
1115 #ifdef INCLUDE_DEBUG_OUTPUT
1116 /* -------------------------------------------------------------------------
1117  * Function   : dump_packet
1118  * Description: Dump the specified data as hex output
1119  * Input      : packet - packet to dump to output
1120  *              length - length of the data in the packet
1121  * Output     : none
1122  * Return     : nothing
1123  * Data Used  : none
1124  * ------------------------------------------------------------------------- */
1125 void
1126 dump_packet(unsigned char* packet, int length)
1127 {
1128   int idx;
1129
1130   OLSR_PRINTF(1, "%s: ", PLUGIN_NAME_SHORT);
1131   for (idx = 0; idx < length; idx++) {
1132     if (idx > 0 && ((idx % 16) == 0))
1133       OLSR_PRINTF(1, "\n%s: ", PLUGIN_NAME_SHORT);
1134     OLSR_PRINTF(1, "%2.2X ", packet[idx]);
1135   }
1136   OLSR_PRINTF(1, "\n");
1137 }
1138 #endif /* INCLUDE_DEBUG_OUTPUT */
1139
1140 /* -------------------------------------------------------------------------
1141  * Function   : check_and_mark_recent_packet
1142  * Description: Wrapper function for the Hash based duplicate check
1143  * Input      : data - pointer to a packet of data to be checked
1144  * Output     : none
1145  * Return     : true if duplicate packet, false otherwise
1146  * Data Used  : P2pdUseHash
1147  * ------------------------------------------------------------------------- */
1148 bool
1149 check_and_mark_recent_packet(unsigned char *data,
1150                              int len __attribute__ ((unused)))
1151 {
1152   unsigned char * ipPacket;
1153   uint16_t ipPacketLen;
1154   uint32_t crc32;
1155
1156   /* If we don't use this filter bail out here */
1157   if (!P2pdUseHash)
1158     return false;
1159     
1160   /* Clean up the hash table each time before we check it */
1161   PrunePacketHistory(NULL);
1162
1163   /* Check for duplicate IP packets now based on a hash */
1164   ipPacket = GetIpPacket(data);
1165   ipPacketLen = GetIpTotalLength(ipPacket);
1166
1167   /* Calculate packet fingerprint */
1168   crc32 = PacketCrc32(ipPacket, ipPacketLen);
1169
1170   /* Check if this packet was seen recently */
1171   if (CheckAndMarkRecentPacket(crc32))
1172   {
1173     OLSR_PRINTF(
1174       8,
1175       "%s: --> discarding: packet is duplicate\n",
1176       PLUGIN_NAME_SHORT);
1177     return true;
1178   }
1179
1180   return false;
1181 }