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