MDNS plugin: Hacked away jet another uninit-warning if DEBUG=0
[olsrd.git] / lib / mdns / src / mdns.c
1
2 /*
3 OLSR MDNS plugin.
4 Written by Saverio Proto <zioproto@gmail.com> and Claudio Pisa <clauz@ninux.org>.
5
6     This file is part of OLSR MDNS PLUGIN.
7
8     The OLSR MDNS PLUGIN is free software: you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation, either version 3 of the License, or
11     (at your option) any later version.
12
13     The OLSR MDNS PLUGIN is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17
18     You should have received a copy of the GNU General Public License
19     along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
20
21
22  */
23
24
25 #include "mdns.h"
26
27 /* System includes */
28 #include <stddef.h>             /* NULL */
29 #include <sys/types.h>          /* ssize_t */
30 #include <string.h>             /* strerror() */
31 #include <stdarg.h>             /* va_list, va_start, va_end */
32 #include <errno.h>              /* errno */
33 #include <assert.h>             /* assert() */
34 #include <linux/if_ether.h>     /* ETH_P_IP */
35 #include <linux/if_packet.h>    /* struct sockaddr_ll, PACKET_MULTICAST */
36 //#include <pthread.h> /* pthread_t, pthread_create() */
37 #include <signal.h>             /* sigset_t, sigfillset(), sigdelset(), SIGINT */
38 #include <netinet/ip.h>         /* struct ip */
39 #include <netinet/udp.h>        /* struct udphdr */
40 #include <unistd.h>             /* close() */
41
42 #include <netinet/in.h>
43 #include <netinet/ip6.h>
44
45 /* OLSRD includes */
46 #include "plugin_util.h"        /* set_plugin_int */
47 #include "defs.h"               /* olsr_cnf, //OLSR_PRINTF */
48 #include "ipcalc.h"
49 #include "olsr.h"               /* //OLSR_PRINTF */
50 #include "mid_set.h"            /* mid_lookup_main_addr() */
51 #include "link_set.h"           /* get_best_link_to_neighbor() */
52 #include "net_olsr.h"           /* ipequal */
53 #include "olsr_logging.h"
54
55 /* plugin includes */
56 #include "NetworkInterfaces.h"  /* TBmfInterface, CreateBmfNetworkInterfaces(), CloseBmfNetworkInterfaces() */
57 #include "Address.h"            /* IsMulticast() */
58 #include "Packet.h"             /* ENCAP_HDR_LEN, BMF_ENCAP_TYPE, BMF_ENCAP_LEN etc. */
59
60 int my_DNS_TTL=0;
61
62 /* -------------------------------------------------------------------------
63  * Function   : PacketReceivedFromOLSR
64  * Description: Handle a received packet from a OLSR message
65  * Input      : ipPacket into an unsigned char and the lenght of the packet
66  * Output     : none
67  * Return     : none
68  * Data Used  : BmfInterfaces
69  * ------------------------------------------------------------------------- */
70 static void
71 PacketReceivedFromOLSR(unsigned char *encapsulationUdpData, int len)
72 {
73   struct ip *ipHeader;                 /* IP header inside the encapsulated IP packet */
74   struct ip6_hdr *ip6Header;                 /* IP header inside the encapsulated IP packet */
75   //union olsr_ip_addr mcSrc;            /* Original source of the encapsulated multicast packet */
76   //union olsr_ip_addr mcDst;            /* Multicast destination of the encapsulated packet */
77   struct TBmfInterface *walker;
78   int stripped_len = 0;
79   ipHeader = (struct ip *)(ARM_NOWARN_ALIGN)encapsulationUdpData;
80   ip6Header = (struct ip6_hdr *)(ARM_NOWARN_ALIGN)encapsulationUdpData;
81   //mcSrc.v4 = ipHeader->ip_src;
82   //mcDst.v4 = ipHeader->ip_dst;
83   OLSR_DEBUG(LOG_PLUGINS, "MDNS PLUGIN got packet from OLSR message\n");
84
85
86   /* Check with each network interface what needs to be done on it */
87   for (walker = BmfInterfaces; walker != NULL; walker = walker->next) {
88     /* To a non-OLSR interface: unpack the encapsulated IP packet and forward it */
89     if (walker->olsrIntf == NULL) {
90       int nBytesWritten;
91       struct sockaddr_ll dest;
92
93       memset(&dest, 0, sizeof(dest));
94       dest.sll_family = AF_PACKET;
95       if ((encapsulationUdpData[0] & 0xf0) == 0x40) {
96         dest.sll_protocol = htons(ETH_P_IP);
97         stripped_len = ntohs(ipHeader->ip_len);
98         }
99       if ((encapsulationUdpData[0] & 0xf0) == 0x60) {
100         dest.sll_protocol = htons(ETH_P_IPV6);
101         stripped_len = 40 + ntohs(ip6Header->ip6_plen); //IPv6 Header size (40) + payload_len 
102         }
103       // Sven-Ola: Don't know how to handle the "stripped_len is uninitialized" condition, maybe exit(1) is better...?
104       if (0 == stripped_len) return;
105       //TODO: if packet is not IP die here
106       
107       if (stripped_len > len) {
108         OLSR_DEBUG(LOG_PLUGINS, "MDNS: Stripped len bigger than len ??\n");
109         }
110       dest.sll_ifindex = if_nametoindex(walker->ifName);
111       dest.sll_halen = IFHWADDRLEN;
112
113       /* Use all-ones as destination MAC address. When the IP destination is
114        * a multicast address, the destination MAC address should normally also
115        * be a multicast address. E.g., when the destination IP is 224.0.0.1,
116        * the destination MAC should be 01:00:5e:00:00:01. However, it does not
117        * seem to matter when the destination MAC address is set to all-ones
118        * in that case. */
119       memset(dest.sll_addr, 0xFF, IFHWADDRLEN);
120
121       nBytesWritten = sendto(walker->capturingSkfd, encapsulationUdpData, stripped_len, 0, (struct sockaddr *)&dest, sizeof(dest));
122       if (nBytesWritten != stripped_len) {
123         BmfPError("sendto() error forwarding unpacked encapsulated pkt on \"%s\"", walker->ifName);
124       } else {
125
126         //OLSR_PRINTF(
127         //  2,
128         //  "%s: --> unpacked and forwarded on \"%s\"\n",
129         //  PLUGIN_NAME_SHORT,
130         //  walker->ifName);
131       }
132     }                           /* if (walker->olsrIntf == NULL) */
133   }
134 }                               /* PacketReceivedFromOLSR */
135
136
137
138 void
139 olsr_parser(union olsr_message *m, struct interface *in_if __attribute__ ((unused)),
140     union olsr_ip_addr *ipaddr, enum duplicate_status status __attribute__ ((unused)))
141 {
142   union olsr_ip_addr originator;
143   int size;
144   uint32_t vtime;
145   OLSR_DEBUG(LOG_PLUGINS, "MDNS PLUGIN: Received msg in parser\n");
146   /* Fetch the originator of the messsage */
147   if (olsr_cnf->ip_version == AF_INET) {
148     memcpy(&originator, &m->v4.originator, olsr_cnf->ipsize);
149     vtime = me_to_reltime(m->v4.olsr_vtime);
150     size = ntohs(m->v4.olsr_msgsize);
151   } else {
152     memcpy(&originator, &m->v6.originator, olsr_cnf->ipsize);
153     vtime = me_to_reltime(m->v6.olsr_vtime);
154     size = ntohs(m->v6.olsr_msgsize);
155   }
156
157   /* Check if message originated from this node.
158    *         If so - back off */
159   if (olsr_ipcmp(&originator, &olsr_cnf->router_id) == 0)
160     return;
161
162   /* Check that the neighbor this message was received from is symmetric.
163    *         If not - back off*/
164   if (check_neighbor_link(ipaddr) != SYM_LINK) {
165     //struct ipaddr_str strbuf;
166     //OLSR_PRINTF(3, "NAME PLUGIN: Received msg from NON SYM neighbor %s\n", olsr_ip_to_string(&strbuf, ipaddr));
167     return;
168   }
169
170   if (olsr_cnf->ip_version == AF_INET) {
171     PacketReceivedFromOLSR((unsigned char *)&m->v4.message, size - 12);
172   } else {
173     PacketReceivedFromOLSR((unsigned char *)&m->v6.message, size - 12 - 96);
174   }
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   char buffer[10240];
183   int aligned_size;
184   union olsr_message *message = (union olsr_message *)buffer;
185   struct interface *ifn;
186   
187   aligned_size=len;
188
189 if ((aligned_size % 4) != 0) {
190     aligned_size = (aligned_size - (aligned_size % 4)) + 4;
191   }
192
193   /* fill message */
194   if (olsr_cnf->ip_version == AF_INET) {
195     /* IPv4 */
196     message->v4.olsr_msgtype = MESSAGE_TYPE;
197     message->v4.olsr_vtime = reltime_to_me(MDNS_VALID_TIME * MSEC_PER_SEC);
198     memcpy(&message->v4.originator, &olsr_cnf->router_id, olsr_cnf->ipsize);
199     //message->v4.ttl = MAX_TTL;
200     if (my_MDNS_TTL) message->v4.ttl = my_MDNS_TTL;
201     else message->v4.ttl = MAX_TTL;
202     message->v4.hopcnt = 0;
203     message->v4.seqno = htons(get_msg_seqno());
204
205     message->v4.olsr_msgsize = htons(aligned_size + 12);
206
207     memset(&message->v4.message, 0, aligned_size);
208     memcpy(&message->v4.message, packet, len);
209     aligned_size = aligned_size + 12;
210   } else {
211     /* IPv6 */
212     message->v6.olsr_msgtype = MESSAGE_TYPE;
213     message->v6.olsr_vtime = reltime_to_me(MDNS_VALID_TIME * MSEC_PER_SEC);
214     memcpy(&message->v6.originator, &olsr_cnf->router_id, olsr_cnf->ipsize);
215     //message->v6.ttl = MAX_TTL;
216     if (my_MDNS_TTL) message->v6.ttl = my_MDNS_TTL;
217     else message->v6.ttl = MAX_TTL;
218     message->v6.hopcnt = 0;
219     message->v6.seqno = htons(get_msg_seqno());
220
221     message->v6.olsr_msgsize = htons(aligned_size + 12 + 96);
222     memset(&message->v6.message, 0, aligned_size);
223     memcpy(&message->v6.message, packet, len);
224     aligned_size = aligned_size + 12 + 96;
225   }
226
227   /* looping trough interfaces */
228   OLSR_FOR_ALL_INTERFACES(ifn) {
229     //OLSR_PRINTF(1, "MDNS PLUGIN: Generating packet - [%s]\n", ifn->int_name);
230
231     if (net_outbuffer_push(ifn, message, aligned_size) != aligned_size) {
232       /* send data and try again */
233       net_output(ifn);
234       if (net_outbuffer_push(ifn, message, aligned_size) != aligned_size) {
235         //OLSR_PRINTF(1, "MDNS PLUGIN: could not send on interface: %s\n", ifn->int_name);
236       }
237     }
238   }
239   OLSR_FOR_ALL_INTERFACES_END(ifn);
240 }
241
242 /* -------------------------------------------------------------------------
243  * Function   : BmfPError
244  * Description: Prints an error message at OLSR debug level 1.
245  *              First the plug-in name is printed. Then (if format is not NULL
246  *              and *format is not empty) the arguments are printed, followed
247  *              by a colon and a blank. Then the message and a new-line.
248  * Input      : format, arguments
249  * Output     : none
250  * Return     : none
251  * Data Used  : none
252  * ------------------------------------------------------------------------- */
253
254 void
255 BmfPError(const char *format, ...)
256 {
257 #define MAX_STR_DESC 255
258   char strDesc[MAX_STR_DESC];
259
260 #if !defined REMOVE_LOG_DEBUG
261   char *stringErr = strerror(errno);
262 #endif
263   /* Rely on short-circuit boolean evaluation */
264   if (format == NULL || *format == '\0') {
265     OLSR_DEBUG(LOG_PLUGINS, "%s: %s\n", PLUGIN_NAME, stringErr);
266   } else {
267     va_list arglist;
268
269     va_start(arglist, format);
270     vsnprintf(strDesc, MAX_STR_DESC, format, arglist);
271     va_end(arglist);
272
273     strDesc[MAX_STR_DESC - 1] = '\0';   /* Ensures null termination */
274
275     OLSR_DEBUG(LOG_PLUGINS, "%s: %s\n", strDesc, stringErr);
276   }
277 }                               /* BmfPError */
278
279 /* -------------------------------------------------------------------------
280  * Function   : MainAddressOf
281  * Description: Lookup the main address of a node
282  * Input      : ip - IP address of the node
283  * Output     : none
284  * Return     : The main IP address of the node
285  * Data Used  : none
286  * ------------------------------------------------------------------------- */
287 union olsr_ip_addr *
288 MainAddressOf(union olsr_ip_addr *ip)
289 {
290   union olsr_ip_addr *result;
291
292   /* TODO: mid_lookup_main_addr() is not thread-safe! */
293   result = olsr_lookup_main_addr_by_alias(ip);
294   if (result == NULL) {
295     result = ip;
296   }
297   return result;
298 }                               /* MainAddressOf */
299
300
301 /* -------------------------------------------------------------------------
302  * Function   : BmfPacketCaptured
303  * Description: Handle a captured IP packet
304  * Input      : intf - the network interface on which the packet was captured
305  *              sllPkttype - the type of packet. Either PACKET_OUTGOING,
306  *                PACKET_BROADCAST or PACKET_MULTICAST.
307  *              encapsulationUdpData - space for the encapsulation header, followed by
308  *                the captured IP packet
309  * Output     : none
310  * Return     : none
311  * Data Used  : BmfInterfaces
312  * Notes      : The IP packet is assumed to be captured on a socket of family
313  *              PF_PACKET and type SOCK_DGRAM (cooked).
314  * ------------------------------------------------------------------------- */
315 static void
316 BmfPacketCaptured(
317                    //struct TBmfInterface* intf,
318                    //unsigned char sllPkttype,
319                    unsigned char *encapsulationUdpData, int nBytes)
320 {
321   union olsr_ip_addr src;              /* Source IP address in captured packet */
322   union olsr_ip_addr dst;              /* Destination IP address in captured packet */
323   union olsr_ip_addr *origIp;          /* Main OLSR address of source of captured packet */
324   struct ip *ipHeader;                 /* The IP header inside the captured IP packet */
325   struct ip6_hdr *ipHeader6;           /* The IP header inside the captured IP packet */
326   struct udphdr *udpHeader;
327   u_int16_t destPort;
328
329   if ((encapsulationUdpData[0] & 0xf0) == 0x40) {       //IPV4
330
331     ipHeader = (struct ip *)(ARM_NOWARN_ALIGN)encapsulationUdpData;
332
333     dst.v4 = ipHeader->ip_dst;
334
335     /* Only forward multicast packets. If configured, also forward local broadcast packets */
336     if (IsMulticast(&dst)) {
337       /* continue */
338     } else {
339       return;
340     }
341     if (ipHeader->ip_p != SOL_UDP) {
342       /* Not UDP */
343       //OLSR_PRINTF(1,"NON UDP PACKET\n");
344       return;                   /* for */
345     }
346     udpHeader = (struct udphdr *)(ARM_NOWARN_ALIGN)(encapsulationUdpData + GetIpHeaderLength(encapsulationUdpData));
347     destPort = ntohs(udpHeader->dest);
348     if (destPort != 5353) {
349       return;
350     }
351   }                             //END IPV4
352
353   else if ((encapsulationUdpData[0] & 0xf0) == 0x60) {  //IPv6
354
355     ipHeader6 = (struct ip6_hdr *)(ARM_NOWARN_ALIGN)encapsulationUdpData;
356     if (ipHeader6->ip6_dst.s6_addr[0] == 0xff)  //Multicast
357     {
358       //Continua
359     } else {
360       return;                   //not multicast
361     }
362     if (ipHeader6->ip6_nxt != SOL_UDP) {
363       /* Not UDP */
364       //OLSR_PRINTF(1,"NON UDP PACKET\n");
365       return;                   /* for */
366     }
367     udpHeader = (struct udphdr *)(ARM_NOWARN_ALIGN)(encapsulationUdpData + 40);
368     destPort = ntohs(udpHeader->dest);
369     if (destPort != 5353) {
370       return;
371     }
372   }                             //END IPV6
373   else
374     return;                     //Is not IP packet
375
376   /* Check if the frame is captured on an OLSR-enabled interface */
377   //isFromOlsrIntf = (intf->olsrIntf != NULL); TODO: put again this check
378
379
380   /* Lookup main address of source in the MID table of OLSR */
381   origIp = MainAddressOf(&src);
382
383   // send the packet to OLSR forward mechanism
384   olsr_mdns_gen(encapsulationUdpData, nBytes);
385 }                               /* BmfPacketCaptured */
386
387
388 /* -------------------------------------------------------------------------
389  * Function   : DoMDNS
390  * Description: This function is registered with the OLSR scheduler and called when something is captured
391  * Input      : none
392  * Output     : none
393  * Return     : none
394  * Data Used  :
395  * ------------------------------------------------------------------------- */
396 void
397 DoMDNS(int skfd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused)))
398 {
399   unsigned char rxBuffer[BMF_BUFFER_SIZE];
400   if (skfd >= 0) {
401     struct sockaddr_ll pktAddr;
402     socklen_t addrLen = sizeof(pktAddr);
403     int nBytes;
404     unsigned char *ipPacket;
405
406     /* Receive the captured Ethernet frame, leaving space for the BMF
407      * encapsulation header */
408     ipPacket = GetIpPacket(rxBuffer);
409     nBytes = recvfrom(skfd, ipPacket, BMF_BUFFER_SIZE,  //TODO: understand how to change this
410                       0, (struct sockaddr *)&pktAddr, &addrLen);
411     if (nBytes < 0) {
412
413       return;                   /* for */
414     }
415
416     /* if (nBytes < 0) */
417     /* Check if the number of received bytes is large enough for an IP
418      * packet which contains at least a minimum-size IP header.
419      * Note: There is an apparent bug in the packet socket implementation in
420      * combination with VLAN interfaces. On a VLAN interface, the value returned
421      * by 'recvfrom' may (but need not) be 4 (bytes) larger than the value
422      * returned on a non-VLAN interface, for the same ethernet frame. */
423     if (nBytes < (int)sizeof(struct ip)) {
424       ////OLSR_PRINTF(
425       //              1,
426       //              "%s: captured frame too short (%d bytes) on \"%s\"\n",
427       //              PLUGIN_NAME,
428       //              nBytes,
429       //              walker->ifName);
430
431       return;                   /* for */
432     }
433
434     if (pktAddr.sll_pkttype == PACKET_OUTGOING ||
435         pktAddr.sll_pkttype == PACKET_MULTICAST || pktAddr.sll_pkttype == PACKET_BROADCAST) {
436       /* A multicast or broadcast packet was captured */
437
438       ////OLSR_PRINTF(
439       //              1,
440       //              "%s: captured frame (%d bytes) on \"%s\"\n",
441       //              PLUGIN_NAME,
442       //              nBytes,
443       //              walker->ifName);
444       //BmfPacketCaptured(walker, pktAddr.sll_pkttype, rxBuffer);
445       BmfPacketCaptured(ipPacket, nBytes);
446
447     }                           /* if (pktAddr.sll_pkttype == ...) */
448   }                             /* if (skfd >= 0 && (FD_ISSET...)) */
449 }                               /* DoMDNS */
450
451 int
452 InitMDNS(struct interface *skipThisIntf)
453 {
454
455
456   //Tells OLSR to launch olsr_parser when the packets for this plugin arrive
457   olsr_parser_add_function(&olsr_parser, PARSER_TYPE);
458   //Creates captures sockets and register them to the OLSR scheduler
459   CreateBmfNetworkInterfaces(skipThisIntf);
460
461   return 0;
462 }                               /* InitMDNS */
463
464 /* -------------------------------------------------------------------------
465  * Function   : CloseMDNS
466  * Description: Close the MDNS plugin and clean up
467  * Input      : none
468  * Output     : none
469  * Return     : none
470  * Data Used  :
471  * ------------------------------------------------------------------------- */
472 void
473 CloseMDNS(void)
474 {
475   CloseBmfNetworkInterfaces();
476 }