43b4e9cc63e854298250ac6012b043cfd76d3ac4
[olsrd.git] / lib / arprefresh / src / olsrd_arprefresh.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 /*
43  * Plugin to refresh the local ARP cache from received OLSR broadcasts
44  */
45
46 #include <stdio.h>
47 #include <string.h>
48 #include <stdlib.h>
49 #include <fcntl.h>
50 #include <sys/ioctl.h>
51 #include <sys/socket.h>
52 #include <net/if.h>
53 #include <net/if_arp.h>
54 #include <net/ethernet.h>
55 #include <netinet/ip.h>
56 #include <netinet/udp.h>
57 #include <netpacket/packet.h>
58 #include <linux/types.h>
59 #include <linux/filter.h>
60 #include <errno.h>
61 #include <unistd.h>
62
63 #include "olsrd_arprefresh.h"
64 #include "kernel_routes.h"
65 #include "scheduler.h"
66 #include "misc.h"
67
68 #undef ARPREFRESH_DEBUG
69 #define PLUGIN_INTERFACE_VERSION 5
70
71 /****************************************************************************
72  *                Functions that the plugin MUST provide                    *
73  ****************************************************************************/
74
75 /**
76  * Plugin interface version
77  * Used by main olsrd to check plugin interface version
78  */
79 int olsrd_plugin_interface_version(void)
80 {
81         return PLUGIN_INTERFACE_VERSION;
82 }
83
84 static const struct olsrd_plugin_parameters plugin_parameters[] = {
85 };
86
87 void olsrd_get_plugin_parameters(const struct olsrd_plugin_parameters **params, int *size)
88 {
89     *params = plugin_parameters;
90     *size = ARRAYSIZE(plugin_parameters);
91 }
92
93 typedef struct
94 {
95         struct ethhdr eth;
96         struct iphdr ip;
97         struct udphdr udp;
98 } __attribute__((packed)) arprefresh_buf;
99
100 static int arprefresh_sockfd = -1;
101 static struct olsr_cookie_info *arp_event_timer_cookie;
102
103 /**
104  * Scheduled event to fetch gathered packets and update the ARP cache
105  * called from olsrd main thread
106  */
107 static void olsr_arp_event(void* foo __attribute__((unused)))
108 {
109         if (0 <= arprefresh_sockfd)
110         {
111                 arprefresh_buf buf;
112                 struct sockaddr_ll from;
113                 socklen_t fromlen = sizeof(from);
114
115                 /*
116                  * Grab a single snapshot on the packet socket. This only works
117                  * if not too much IP traffic is currently flowing through.
118                  */
119                 ssize_t size = recvfrom(arprefresh_sockfd, &buf, sizeof(buf),
120                         MSG_TRUNC, (struct sockaddr *)&from, &fromlen);
121
122                 if (0 <= size &&
123                     size >= (ssize_t)sizeof(buf) /*** &&
124                     ETH_P_IP == ntohs(buf.eth.h_proto) &&
125                     IPPROTO_UDP == buf.ip.protocol &&
126                     arprefresh_portnum == ntohs(buf.udp.source) &&
127                     arprefresh_portnum == ntohs(buf.udp.dest) ***/)
128                 {
129                         union
130                         {
131                                 struct arpreq arp;
132                                 struct sockaddr_in in_pa;
133                                 struct sockaddr_in6 in_pa6;
134                         } req;
135
136                         memset(&req, 0, sizeof(req));
137                         req.in_pa.sin_family = AF_INET;
138                         memcpy(&req.in_pa.sin_addr, &buf.ip.saddr, sizeof(buf.ip.saddr));
139                         req.arp.arp_ha.sa_family = AF_LOCAL;
140                         memcpy(&req.arp.arp_ha.sa_data, &buf.eth.h_source, sizeof(buf.eth.h_source));
141                         req.arp.arp_flags = ATF_COM;
142                         if_indextoname(from.sll_ifindex, req.arp.arp_dev);
143 #ifdef ARPREFRESH_DEBUG
144                         {
145                                 int i;
146                                 OLSR_PRINTF(0, "Refresh on %s, %s=", req.arp.arp_dev,
147                                         inet_ntoa(*((struct in_addr*)&buf.ip.saddr)));
148                                 for(i = 0; i < (ssize_t)sizeof(buf.eth.h_source); i++)
149                                 {
150                                         OLSR_PRINTF(0, "%02x%s", ((unsigned char *)&buf.eth.h_source)[i], i < (ssize_t)sizeof(buf.eth.h_source) -1 ? ":" : "\n");
151                                 }
152                         }
153 #endif
154                         if (ioctl(arprefresh_sockfd, SIOCSARP, &req) < 0) {
155                                 OLSR_PRINTF(1, "*** ARPREFRESH: SIOCSARP: %s\n", strerror(errno));
156                                 close(arprefresh_sockfd);
157                                 arprefresh_sockfd = -1;
158                                 return;
159                         }
160                 }
161         }
162 }
163
164 /**
165  * Initialize plugin
166  * Called after all parameters are passed
167  */
168 int olsrd_plugin_init(void)
169 {
170         int ret = 0;
171         arp_event_timer_cookie  = olsr_alloc_cookie("Arprefresh: event", OLSR_COOKIE_TYPE_TIMER);
172         if (AF_INET == olsr_cnf->ip_version)
173         {
174                 struct sock_fprog filter;
175                 struct sock_filter BPF_code[]=
176                 {
177                         /* tcpdump -s [sizeof(arprefresh_buf)] -ni lo udp and dst port [arprefresh_portnum] -dd */
178                         { 0x28, 0, 0, 0x0000000c },
179                         { 0x15, 0, 4, 0x000086dd },
180                         { 0x30, 0, 0, 0x00000014 },
181                         { 0x15, 0, 11, 0x00000011 },
182                         { 0x28, 0, 0, 0x00000038 },
183                         { 0x15, 8, 9, olsr_cnf->olsr_port },
184                         { 0x15, 0, 8, 0x00000800 },
185                         { 0x30, 0, 0, 0x00000017 },
186                         { 0x15, 0, 6, 0x00000011 },
187                         { 0x28, 0, 0, 0x00000014 },
188                         { 0x45, 4, 0, 0x00001fff },
189                         { 0xb1, 0, 0, 0x0000000e },
190                         { 0x48, 0, 0, 0x00000010 },
191                         { 0x15, 0, 1, olsr_cnf->olsr_port },
192                         { 0x6, 0, 0, sizeof(arprefresh_buf) },
193                         { 0x6, 0, 0, 0x00000000 }
194                 };
195                 filter.len = ARRAYSIZE(BPF_code);
196                 filter.filter = BPF_code;
197                 if (0 <= (arprefresh_sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) &&
198                     0 <= set_nonblocking(arprefresh_sockfd) &&
199                     0 <= setsockopt(arprefresh_sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)))
200                 {
201                         /* Register the ARP refresh event */
202                         olsr_start_timer(2 * MSEC_PER_SEC, 0, OLSR_TIMER_PERIODIC,
203                                          &olsr_arp_event, NULL, arp_event_timer_cookie->ci_id);
204                         ret = 1;
205                 }
206                 else
207                 {
208                         OLSR_PRINTF(1, "*** ARPREFRESH: Cannot create non-blocking filtering packet socket: %s\n", strerror(errno));
209                 }
210         }
211         else
212         {
213                 OLSR_PRINTF(1, "*** ARPREFRESH: IPv6 not supported\n");
214         }
215         return ret;
216 }
217
218 /****************************************************************************
219  *       Optional private constructor and destructor functions              *
220  ****************************************************************************/
221
222 static void __attribute__ ((constructor)) my_init(void);
223 static void __attribute__ ((destructor)) my_fini(void);
224
225 static void my_init(void)
226 {
227         printf("OLSRD arprefresh plugin by Sven-Ola\n");
228 }
229
230 /**
231  * Optional Private Destructor
232  */
233 static void my_fini(void)
234 {
235         if (0 <= arprefresh_sockfd)
236         {
237                 close(arprefresh_sockfd);
238                 arprefresh_sockfd = -1;
239         }
240 }
241
242 /*
243  * Local Variables:
244  * c-basic-offset: 2
245  * indent-tabs-mode: nil
246  * End:
247  */