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