mDNS: Skeleton code for new host filter feature in mDNS plugin
[olsrd.git] / lib / mdns / src / mdns.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 "mdns.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 <linux/if_ether.h>     /* ETH_P_IP */
52 #include <linux/if_packet.h>    /* struct sockaddr_ll, PACKET_MULTICAST */
53 //#include <pthread.h> /* pthread_t, pthread_create() */
54 #include <signal.h>             /* sigset_t, sigfillset(), sigdelset(), SIGINT */
55 #include <netinet/ip.h>         /* struct ip */
56 #include <netinet/udp.h>        /* struct udphdr */
57 #include <unistd.h>             /* close() */
58
59 #include <netinet/in.h>
60 #include <netinet/ip6.h>
61
62 /* OLSRD includes */
63 #include "plugin_util.h"        /* set_plugin_int */
64 #include "defs.h"               /* olsr_cnf, //OLSR_PRINTF */
65 #include "ipcalc.h"
66 #include "olsr.h"               /* //OLSR_PRINTF */
67 #include "mid_set.h"            /* mid_lookup_main_addr() */
68 #include "link_set.h"           /* get_best_link_to_neighbor() */
69 #include "net_olsr.h"           /* ipequal */
70
71 /* plugin includes */
72 #include "NetworkInterfaces.h"  /* TBmfInterface, CreateBmfNetworkInterfaces(), CloseBmfNetworkInterfaces() */
73 #include "Address.h"            /* IsMulticast() */
74 #include "Packet.h"             /* ENCAP_HDR_LEN, BMF_ENCAP_TYPE, BMF_ENCAP_LEN etc. */
75 #include "list_backport.h"
76
77 #define OLSR_FOR_ALL_FILTEREDNODES_ENTRIES(n, iterator) list_for_each_element_safe(&ListOfFilteredHosts, n, list, iterator)
78
79 struct list_entity ListOfFilteredHosts;
80
81 /* -------------------------------------------------------------------------
82  * Function   : PacketReceivedFromOLSR
83  * Description: Handle a received packet from a OLSR message
84  * Input      : ipPacket into an unsigned char and the lenght of the packet
85  * Output     : none
86  * Return     : none
87  * Data Used  : BmfInterfaces
88  * ------------------------------------------------------------------------- */
89 static void
90 PacketReceivedFromOLSR(unsigned char *encapsulationUdpData, int len)
91 {
92   struct ip *ipHeader;                 /* IP header inside the encapsulated IP packet */
93   struct ip6_hdr *ip6Header;                 /* IP header inside the encapsulated IP packet */
94   //union olsr_ip_addr mcSrc;            /* Original source of the encapsulated multicast packet */
95   //union olsr_ip_addr mcDst;            /* Multicast destination of the encapsulated packet */
96   struct TBmfInterface *walker;
97   int stripped_len = 0;
98   ipHeader = (struct ip *)ARM_NOWARN_ALIGN(encapsulationUdpData);
99   ip6Header = (struct ip6_hdr *)ARM_NOWARN_ALIGN(encapsulationUdpData);
100
101   //mcSrc.v4 = ipHeader->ip_src;
102   //mcDst.v4 = ipHeader->ip_dst;
103   //OLSR_DEBUG(LOG_PLUGINS, "MDNS PLUGIN got packet from OLSR message\n");
104
105
106   /* Check with each network interface what needs to be done on it */
107   for (walker = BmfInterfaces; walker != NULL; walker = walker->next) {
108     /* To a non-OLSR interface: unpack the encapsulated IP packet and forward it */
109     if (walker->olsrIntf == NULL) {
110       int nBytesWritten;
111       struct sockaddr_ll dest;
112
113       memset(&dest, 0, sizeof(dest));
114       dest.sll_family = AF_PACKET;
115       if ((encapsulationUdpData[0] & 0xf0) == 0x40) {
116         dest.sll_protocol = htons(ETH_P_IP);
117         stripped_len = ntohs(ipHeader->ip_len);
118         ipHeader->ip_ttl = (u_int8_t) 1; //setting up TTL to 1 to avoid mdns packets flood 
119         }
120       if ((encapsulationUdpData[0] & 0xf0) == 0x60) {
121         dest.sll_protocol = htons(ETH_P_IPV6);
122         stripped_len = 40 + ntohs(ip6Header->ip6_plen); //IPv6 Header size (40) + payload_len 
123         ip6Header->ip6_hops = (uint8_t) 1; //setting up Hop Limit to 1 to avoid mdns packets flood
124         }
125       // Sven-Ola: Don't know how to handle the "stripped_len is uninitialized" condition, maybe exit(1) is better...?
126       if (0 == stripped_len) return;
127       //TODO: if packet is not IP die here
128       
129       if (stripped_len > len) {
130         //OLSR_DEBUG(LOG_PLUGINS, "MDNS: Stripped len bigger than len ??\n");
131         }
132       dest.sll_ifindex = if_nametoindex(walker->ifName);
133       dest.sll_halen = IFHWADDRLEN;
134
135       /* Use all-ones as destination MAC address. When the IP destination is
136        * a multicast address, the destination MAC address should normally also
137        * be a multicast address. E.g., when the destination IP is 224.0.0.1,
138        * the destination MAC should be 01:00:5e:00:00:01. However, it does not
139        * seem to matter when the destination MAC address is set to all-ones
140        * in that case. */
141       memset(dest.sll_addr, 0xFF, IFHWADDRLEN);
142       
143       nBytesWritten = sendto(walker->capturingSkfd, encapsulationUdpData, stripped_len, 0, (struct sockaddr *)&dest, sizeof(dest));
144       if (nBytesWritten != stripped_len) {
145         BmfPError("sendto() error forwarding unpacked encapsulated pkt on \"%s\"", walker->ifName);
146       } else {
147
148         //OLSR_PRINTF(
149         //  2,
150         //  "%s: --> unpacked and forwarded on \"%s\"\n",
151         //  PLUGIN_NAME_SHORT,
152         //  walker->ifName);
153       }
154     }                           /* if (walker->olsrIntf == NULL) */
155   }
156 }                               /* PacketReceivedFromOLSR */
157
158
159 bool
160 olsr_parser(union olsr_message *m, struct interface *in_if __attribute__ ((unused)), union olsr_ip_addr *ipaddr)
161 {
162   union olsr_ip_addr originator;
163   int size;
164   //OLSR_DEBUG(LOG_PLUGINS, "MDNS PLUGIN: Received msg in parser\n");
165   /* Fetch the originator of the messsage */
166   if (olsr_cnf->ip_version == AF_INET) {
167     memcpy(&originator, &m->v4.originator, olsr_cnf->ipsize);
168     size = ntohs(m->v4.olsr_msgsize);
169   } else {
170     memcpy(&originator, &m->v6.originator, olsr_cnf->ipsize);
171     size = ntohs(m->v6.olsr_msgsize);
172   }
173
174   /* Check if message originated from this node.
175    *         If so - back off */
176   if (ipequal(&originator, &olsr_cnf->main_addr))
177     return false;
178
179   /* Check that the neighbor this message was received from is symmetric.
180    *         If not - back off*/
181   if (check_neighbor_link(ipaddr) != SYM_LINK) {
182     //struct ipaddr_str strbuf;
183     //OLSR_PRINTF(3, "NAME PLUGIN: Received msg from NON SYM neighbor %s\n", olsr_ip_to_string(&strbuf, ipaddr));
184     return false;
185   }
186
187   if (olsr_cnf->ip_version == AF_INET) {
188     PacketReceivedFromOLSR((unsigned char *)&m->v4.message, size - 12);
189   } else {
190     PacketReceivedFromOLSR((unsigned char *)&m->v6.message, size - 12 - 96);
191   }
192 //forward the message
193 return true;
194 }
195
196 //Sends a packet in the OLSR network
197 void
198 olsr_mdns_gen(unsigned char *packet, int len)
199 {
200   /* send buffer: huge */
201   char buffer[10240];
202   int aligned_size;
203   union olsr_message *message = (union olsr_message *)buffer;
204   struct interface *ifn;
205   
206   aligned_size=len;
207
208 if ((aligned_size % 4) != 0) {
209     aligned_size = (aligned_size - (aligned_size % 4)) + 4;
210   }
211
212   /* fill message */
213   if (olsr_cnf->ip_version == AF_INET) {
214     /* IPv4 */
215     message->v4.olsr_msgtype = MESSAGE_TYPE;
216     message->v4.olsr_vtime = reltime_to_me(MDNS_VALID_TIME * MSEC_PER_SEC);
217     memcpy(&message->v4.originator, &olsr_cnf->main_addr, olsr_cnf->ipsize);
218     //message->v4.ttl = MAX_TTL;
219     if (my_MDNS_TTL) message->v4.ttl = my_MDNS_TTL;
220     else message->v4.ttl = MAX_TTL;
221     message->v4.hopcnt = 0;
222     message->v4.seqno = htons(get_msg_seqno());
223
224     message->v4.olsr_msgsize = htons(aligned_size + 12);
225
226     memset(&message->v4.message, 0, aligned_size);
227     memcpy(&message->v4.message, packet, len);
228     aligned_size = aligned_size + 12;
229   } else {
230     /* IPv6 */
231     message->v6.olsr_msgtype = MESSAGE_TYPE;
232     message->v6.olsr_vtime = reltime_to_me(MDNS_VALID_TIME * MSEC_PER_SEC);
233     memcpy(&message->v6.originator, &olsr_cnf->main_addr, olsr_cnf->ipsize);
234     //message->v6.ttl = MAX_TTL;
235     if (my_MDNS_TTL) message->v6.ttl = my_MDNS_TTL;
236     else message->v6.ttl = MAX_TTL;
237     message->v6.hopcnt = 0;
238     message->v6.seqno = htons(get_msg_seqno());
239
240     message->v6.olsr_msgsize = htons(aligned_size + 12 + 96);
241     memset(&message->v6.message, 0, aligned_size);
242     memcpy(&message->v6.message, packet, len);
243     aligned_size = aligned_size + 12 + 96;
244   }
245
246   /* looping trough interfaces */
247  for (ifn = ifnet; ifn; ifn = ifn->int_next) {
248     //OLSR_PRINTF(1, "MDNS PLUGIN: Generating packet - [%s]\n", ifn->int_name);
249
250     if (net_outbuffer_push(ifn, message, aligned_size) != aligned_size) {
251       /* send data and try again */
252       net_output(ifn);
253       if (net_outbuffer_push(ifn, message, aligned_size) != aligned_size) {
254         //OLSR_PRINTF(1, "MDNS PLUGIN: could not send on interface: %s\n", ifn->int_name);
255       }
256     }
257   }
258 }
259
260 /* -------------------------------------------------------------------------
261  * Function   : BmfPError
262  * Description: Prints an error message at OLSR debug level 1.
263  *              First the plug-in name is printed. Then (if format is not NULL
264  *              and *format is not empty) the arguments are printed, followed
265  *              by a colon and a blank. Then the message and a new-line.
266  * Input      : format, arguments
267  * Output     : none
268  * Return     : none
269  * Data Used  : none
270  * ------------------------------------------------------------------------- */
271
272 void
273 BmfPError(const char *format, ...)
274 {
275 #define MAX_STR_DESC 255
276   char strDesc[MAX_STR_DESC];
277
278 #if !defined REMOVE_LOG_DEBUG
279   //char *stringErr = strerror(errno);
280 #endif
281   /* Rely on short-circuit boolean evaluation */
282   if (format == NULL || *format == '\0') {
283     //OLSR_DEBUG(LOG_PLUGINS, "%s: %s\n", PLUGIN_NAME, stringErr);
284   } else {
285     va_list arglist;
286
287     va_start(arglist, format);
288     vsnprintf(strDesc, MAX_STR_DESC, format, arglist);
289     va_end(arglist);
290
291     strDesc[MAX_STR_DESC - 1] = '\0';   /* Ensures null termination */
292
293     //OLSR_DEBUG(LOG_PLUGINS, "%s: %s\n", strDesc, stringErr);
294   }
295 }                               /* BmfPError */
296
297 /* -------------------------------------------------------------------------
298  * Function   : MainAddressOf
299  * Description: Lookup the main address of a node
300  * Input      : ip - IP address of the node
301  * Output     : none
302  * Return     : The main IP address of the node
303  * Data Used  : none
304  * ------------------------------------------------------------------------- */
305 union olsr_ip_addr *
306 MainAddressOf(union olsr_ip_addr *ip)
307 {
308   union olsr_ip_addr *result;
309
310   /* TODO: mid_lookup_main_addr() is not thread-safe! */
311   result = mid_lookup_main_addr(ip);
312   if (result == NULL) {
313     result = ip;
314   }
315   return result;
316 }                               /* MainAddressOf */
317
318
319 static int
320 isInFilteredList(union olsr_ip_addr *ip) {
321
322         //TODO: implement here check if IP is in filtered list
323
324 return 1;
325
326 }
327
328
329 /* -------------------------------------------------------------------------
330  * Function   : BmfPacketCaptured
331  * Description: Handle a captured IP packet
332  * Input      : intf - the network interface on which the packet was captured
333  *              sllPkttype - the type of packet. Either PACKET_OUTGOING,
334  *                PACKET_BROADCAST or PACKET_MULTICAST.
335  *              encapsulationUdpData - space for the encapsulation header, followed by
336  *                the captured IP packet
337  * Output     : none
338  * Return     : none
339  * Data Used  : BmfInterfaces
340  * Notes      : The IP packet is assumed to be captured on a socket of family
341  *              PF_PACKET and type SOCK_DGRAM (cooked).
342  * ------------------------------------------------------------------------- */
343 static void
344 BmfPacketCaptured(
345                    //struct TBmfInterface* intf,
346                    //unsigned char sllPkttype,
347                    unsigned char *encapsulationUdpData, int nBytes)
348 {
349   union olsr_ip_addr dst;              /* Destination IP address in captured packet */
350   union olsr_ip_addr src;              
351   struct ip *ipHeader;                 /* The IP header inside the captured IP packet */
352   struct ip6_hdr *ipHeader6;           /* The IP header inside the captured IP packet */
353   struct udphdr *udpHeader;
354   u_int16_t destPort;
355
356   if ((encapsulationUdpData[0] & 0xf0) == 0x40) {       //IPV4
357
358     ipHeader = (struct ip *)ARM_NOWARN_ALIGN(encapsulationUdpData);
359
360     dst.v4 = ipHeader->ip_dst;
361     src.v4 = ipHeader->ip_src;
362
363     /* Only forward multicast packets. If configured, also forward local broadcast packets */
364     if (IsMulticast(&dst)) {
365       /* continue */
366     } else {
367       return;
368     }
369     if (ipHeader->ip_p != SOL_UDP) {
370       /* Not UDP */
371       //OLSR_PRINTF(1,"NON UDP PACKET\n");
372       return;                   /* for */
373     }
374     udpHeader = (struct udphdr *)ARM_NOWARN_ALIGN(encapsulationUdpData + GetIpHeaderLength(encapsulationUdpData));
375     destPort = ntohs(udpHeader->dest);
376     if (destPort != 5353) {
377       return;
378     }
379     if(((u_int8_t) ipHeader->ip_ttl) <= ((u_int8_t) 1))    // Discard mdns packet with TTL limit 1 or less
380       return;
381
382     if (isInFilteredList(&src)) {
383
384         return;
385     }
386
387   }                             //END IPV4
388
389   else if ((encapsulationUdpData[0] & 0xf0) == 0x60) {  //IPv6
390
391     ipHeader6 = (struct ip6_hdr *)ARM_NOWARN_ALIGN(encapsulationUdpData);
392
393     //TODO: mettere dentro src.v6 l'indirizzo IPv6
394
395     if (ipHeader6->ip6_dst.s6_addr[0] == 0xff)  //Multicast
396     {
397       //Continua
398     } else {
399       return;                   //not multicast
400     }
401     if (ipHeader6->ip6_nxt != SOL_UDP) {
402       /* Not UDP */
403       //OLSR_PRINTF(1,"NON UDP PACKET\n");
404       return;                   /* for */
405     }
406     udpHeader = (struct udphdr *)ARM_NOWARN_ALIGN(encapsulationUdpData + 40);
407     destPort = ntohs(udpHeader->dest);
408     if (destPort != 5353) {
409       return;
410     }
411     
412     if(((uint8_t) ipHeader6->ip6_hops) <= ((uint8_t) 1))  // Discard mdns packet with hop limit 1 or less
413       return;
414     
415     if (isInFilteredList(&src)) {
416     
417     return;
418     }
419
420   }                             //END IPV6
421   else
422     return;                     //Is not IP packet
423
424   /* Check if the frame is captured on an OLSR-enabled interface */
425   //isFromOlsrIntf = (intf->olsrIntf != NULL); TODO: put again this check
426
427   // send the packet to OLSR forward mechanism
428   olsr_mdns_gen(encapsulationUdpData, nBytes);
429 }                               /* BmfPacketCaptured */
430
431
432 /* -------------------------------------------------------------------------
433  * Function   : DoMDNS
434  * Description: This function is registered with the OLSR scheduler and called when something is captured
435  * Input      : none
436  * Output     : none
437  * Return     : none
438  * Data Used  :
439  * ------------------------------------------------------------------------- */
440 void
441 DoMDNS(int skfd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused)))
442 {
443   unsigned char rxBuffer[BMF_BUFFER_SIZE];
444   if (skfd >= 0) {
445     struct sockaddr_ll pktAddr;
446     socklen_t addrLen = sizeof(pktAddr);
447     int nBytes;
448     unsigned char *ipPacket;
449
450     /* Receive the captured Ethernet frame, leaving space for the BMF
451      * encapsulation header */
452     ipPacket = GetIpPacket(rxBuffer);
453     nBytes = recvfrom(skfd, ipPacket, BMF_BUFFER_SIZE,  //TODO: understand how to change this
454                       0, (struct sockaddr *)&pktAddr, &addrLen);
455     if (nBytes < 0) {
456
457       return;                   /* for */
458     }
459
460     /* if (nBytes < 0) */
461     /* Check if the number of received bytes is large enough for an IP
462      * packet which contains at least a minimum-size IP header.
463      * Note: There is an apparent bug in the packet socket implementation in
464      * combination with VLAN interfaces. On a VLAN interface, the value returned
465      * by 'recvfrom' may (but need not) be 4 (bytes) larger than the value
466      * returned on a non-VLAN interface, for the same ethernet frame. */
467     if (nBytes < (int)sizeof(struct ip)) {
468       ////OLSR_PRINTF(
469       //              1,
470       //              "%s: captured frame too short (%d bytes) on \"%s\"\n",
471       //              PLUGIN_NAME,
472       //              nBytes,
473       //              walker->ifName);
474
475       return;                   /* for */
476     }
477
478     if (pktAddr.sll_pkttype == PACKET_OUTGOING ||
479         pktAddr.sll_pkttype == PACKET_MULTICAST || pktAddr.sll_pkttype == PACKET_BROADCAST) {
480       /* A multicast or broadcast packet was captured */
481
482       ////OLSR_PRINTF(
483       //              1,
484       //              "%s: captured frame (%d bytes) on \"%s\"\n",
485       //              PLUGIN_NAME,
486       //              nBytes,
487       //              walker->ifName);
488       //BmfPacketCaptured(walker, pktAddr.sll_pkttype, rxBuffer);
489       BmfPacketCaptured(ipPacket, nBytes);
490
491     }                           /* if (pktAddr.sll_pkttype == ...) */
492   }                             /* if (skfd >= 0 && (FD_ISSET...)) */
493 }                               /* DoMDNS */
494
495 int
496 InitMDNS(struct interface *skipThisIntf)
497 {
498    
499   listbackport_init_head(&ListOfFilteredHosts);
500
501   //Tells OLSR to launch olsr_parser when the packets for this plugin arrive
502   olsr_parser_add_function(&olsr_parser, PARSER_TYPE);
503   //Creates captures sockets and register them to the OLSR scheduler
504   CreateBmfNetworkInterfaces(skipThisIntf);
505
506   return 1;
507 }                               /* InitMDNS */
508
509 /* -------------------------------------------------------------------------
510  * Function   : CloseMDNS
511  * Description: Close the MDNS plugin and clean up
512  * Input      : none
513  * Output     : none
514  * Return     : none
515  * Data Used  :
516  * ------------------------------------------------------------------------- */
517 void
518 CloseMDNS(void)
519 {
520   CloseBmfNetworkInterfaces();
521 }