]> git.meshlink.io Git - catta/blob - avahi-autoipd/main.c
8ce7da1ed8d402009791213e131af48e8be1ee5c
[catta] / avahi-autoipd / main.c
1 /* $Id$ */
2
3 /***
4   This file is part of avahi.
5  
6   avahi is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10  
11   avahi is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14   Public License for more details.
15  
16   You should have received a copy of the GNU Lesser General Public
17   License along with avahi; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <sys/socket.h>
29 #include <netpacket/packet.h>
30 #include <net/ethernet.h>
31 #include <fcntl.h>
32 #include <time.h>
33 #include <assert.h>
34 #include <errno.h>
35 #include <string.h>
36 #include <inttypes.h>
37 #include <sys/types.h>
38 #include <arpa/inet.h>
39 #include <sys/ioctl.h>
40 #include <poll.h>
41 #include <net/if.h>
42
43 #include <avahi-common/malloc.h>
44 #include <avahi-common/timeval.h>
45
46 #include <libdaemon/dfork.h>
47 #include <libdaemon/dsignal.h>
48 #include <libdaemon/dlog.h>
49 #include <libdaemon/dpid.h>
50 #include <libdaemon/dexec.h>
51
52 #ifndef __linux__
53 #error "avahi-autoipd is only available on Linux for now"
54 #endif
55
56 /* An implementation of RFC 3927 */
57
58 /* Constants from the RFC */
59 #define PROBE_WAIT 1
60 #define PROBE_NUM 3
61 #define PROBE_MIN 1
62 #define PROBE_MAX 2
63 #define ANNOUNCE_WAIT 2
64 #define ANNOUNCE_NUM 2
65 #define ANNOUNCE_INTERVAL 2
66 #define MAX_CONFLICTS 10
67 #define RATE_LIMIT_INTERVAL 60
68 #define DEFEND_INTERVAL 10
69
70 #define IPV4LL_NETWORK 0xA9FE0000L
71 #define IPV4LL_NETMASK 0xFFFF0000L
72 #define IPV4LL_HOSTMASK 0x0000FFFFL
73
74 #define ETHER_ADDRLEN 6
75 #define ARP_PACKET_SIZE (8+4+4+2*ETHER_ADDRLEN)
76
77 typedef enum State {
78     STATE_INVALID,
79     STATE_WAITING_PROBE,
80     STATE_PROBING,
81     STATE_WAITING_ANNOUNCE,
82     STATE_ANNOUNCING,
83     STATE_RUNNING,
84     STATE_SLEEPING,
85     STATE_MAX
86 } State;
87
88 typedef enum ArpOperation {
89     ARP_REQUEST = 1,
90     ARP_RESPONSE = 2
91 } ArpOperation;
92
93 typedef struct ArpPacketInfo {
94     ArpOperation operation;
95
96     uint32_t sender_ip_address, target_ip_address;
97     uint8_t sender_hw_address[ETHER_ADDRLEN], target_hw_address[ETHER_ADDRLEN];
98 } ArpPacketInfo;
99
100 static State state = STATE_INVALID;
101 static int n_iteration = 0;
102 static int n_conflict = 0;
103
104 #define RANDOM_DEVICE "/dev/urandom"
105
106 static void init_rand_seed(void) {
107     int fd;
108     unsigned seed = 0;
109
110     /* Try to initialize seed from /dev/urandom, to make it a little
111      * less predictable, and to make sure that multiple machines
112      * booted at the same time choose different random seeds.  */
113     if ((fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) {
114         read(fd, &seed, sizeof(seed));
115         close(fd);
116     }
117
118     /* If the initialization failed by some reason, we add the time to the seed */
119     seed ^= (unsigned) time(NULL);
120
121     srand(seed);
122 }
123
124 static uint32_t pick_addr(uint32_t old_addr) {
125     uint32_t addr;
126
127     do {
128         unsigned r = (unsigned) rand();
129
130         /* Reduce to 16 bits */
131         while (r > 0xFFFF)
132             r = (r >> 16) ^ (r & 0xFFFF);
133         
134         addr = htonl(IPV4LL_NETWORK | (uint32_t) r);
135
136     } while (addr == old_addr);
137
138     return addr;
139 }
140
141 static void* packet_new(const ArpPacketInfo *info, size_t *packet_len) {
142     uint8_t *r;
143
144     assert(info);
145     assert(packet_len);
146     assert(info->operation == ARP_REQUEST || info->operation == ARP_RESPONSE);
147
148     *packet_len = ARP_PACKET_SIZE;
149     r = avahi_new0(uint8_t, *packet_len);
150     
151     r[1] = 1; /* HTYPE */
152     r[2] = 8; /* PTYPE */
153     r[4] = ETHER_ADDRLEN; /* HLEN */
154     r[5] = 4; /* PLEN */
155     r[7] = (uint8_t) info->operation;
156
157     memcpy(r+8, info->sender_hw_address, ETHER_ADDRLEN);
158     memcpy(r+14, &info->sender_ip_address, 4);
159     memcpy(r+18, info->target_hw_address, ETHER_ADDRLEN);
160     memcpy(r+24, &info->target_ip_address, 4);
161
162     return r;
163 }
164
165 static void *packet_new_probe(uint32_t ip_address, const uint8_t*hw_address, size_t *packet_len) {
166     ArpPacketInfo info;
167     
168     memset(&info, 0, sizeof(info));
169     info.operation = ARP_REQUEST;
170     memcpy(info.sender_hw_address, hw_address, ETHER_ADDRLEN);
171     info.target_ip_address = ip_address;
172
173     return packet_new(&info, packet_len);
174 }
175
176 static void *packet_new_announcement(uint32_t ip_address, const uint8_t* hw_address, size_t *packet_len) {
177     ArpPacketInfo info;
178
179     memset(&info, 0, sizeof(info));
180     info.operation = ARP_REQUEST;
181     memcpy(info.sender_hw_address, hw_address, ETHER_ADDRLEN);
182     info.target_ip_address = ip_address;
183     info.sender_ip_address = ip_address;
184
185     return packet_new(&info, packet_len);
186 }
187
188 static int packet_parse(const void *data, size_t packet_len, ArpPacketInfo *info) {
189     const uint8_t *p = data;
190     
191     assert(data);
192
193     if (packet_len < ARP_PACKET_SIZE)
194         return -1;
195
196     /* Check HTYPE and PTYPE */
197     if (p[0] != 0 || p[1] != 1 || p[2] != 8 || p[3] != 0)
198         return -1;
199
200     /* Check HLEN, PLEN, OPERATION */
201     if (p[4] != ETHER_ADDRLEN || p[5] != 4 || p[6] != 0 || (p[7] != 1 && p[7] != 2))
202         return -1;
203     
204     info->operation = p[7];
205     memcpy(info->sender_hw_address, p+8, ETHER_ADDRLEN);
206     memcpy(&info->sender_ip_address, p+14, 4);
207     memcpy(info->target_hw_address, p+18, ETHER_ADDRLEN);
208     memcpy(&info->target_ip_address, p+24, 4);
209
210     return 0;
211 }
212
213 static void set_state(State st, int reset_counter) {
214     const char* const state_table[] = {
215         [STATE_INVALID] = "INVALID",
216         [STATE_WAITING_PROBE] = "WAITING_PROBE",
217         [STATE_PROBING] = "PROBING",
218         [STATE_WAITING_ANNOUNCE] = "WAITING_ANNOUNCE", 
219         [STATE_ANNOUNCING] = "ANNOUNCING",
220         [STATE_RUNNING] = "RUNNING",
221         [STATE_SLEEPING] = "SLEEPING"
222     };
223     
224     assert(st < STATE_MAX);
225
226     if (st == state && !reset_counter) {
227         n_iteration++;
228         daemon_log(LOG_DEBUG, "State iteration %s-%i", state_table[state], n_iteration);
229     } else {
230         daemon_log(LOG_DEBUG, "State transition %s-%i -> %s-0", state_table[state], n_iteration, state_table[st]);
231         state = st;
232         n_iteration = 0;
233     }
234 }
235
236 static int add_address(int iface, uint32_t addr) {
237     char buf[64];
238
239     daemon_log(LOG_INFO, "Selected address %s", inet_ntop(AF_INET, &addr, buf, sizeof(buf)));
240     return 0;
241 }
242
243 static int remove_address(int iface, uint32_t addr) {
244     char buf[64];
245     
246     daemon_log(LOG_INFO, "Removing address %s", inet_ntop(AF_INET, &addr, buf, sizeof(buf)));
247     return 0;
248 }
249
250 static int open_socket(int iface, uint8_t *hw_address) {
251     int fd = -1;
252     struct sockaddr_ll sa;
253     socklen_t sa_len;
254     
255     if ((fd = socket(PF_PACKET, SOCK_DGRAM, 0)) < 0) {
256         daemon_log(LOG_ERR, "socket() failed: %s", strerror(errno));
257         goto fail;
258     }
259
260     memset(&sa, 0, sizeof(sa));
261     sa.sll_family = AF_PACKET;
262     sa.sll_protocol = htons(ETH_P_ARP);
263     sa.sll_ifindex = iface;
264
265     if (bind(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) {
266         daemon_log(LOG_ERR, "bind() failed: %s", strerror(errno));
267         goto fail;
268     }
269
270     sa_len = sizeof(sa);
271     if (getsockname(fd, (struct sockaddr*) &sa, &sa_len) < 0) {
272         daemon_log(LOG_ERR, "getsockname() failed: %s", strerror(errno));
273         goto fail;
274     }
275
276     if (sa.sll_halen != ETHER_ADDRLEN) {
277         daemon_log(LOG_ERR, "getsockname() returned invalid hardware address.");
278         goto fail;
279     }
280
281     memcpy(hw_address, sa.sll_addr, ETHER_ADDRLEN);
282
283     return fd;
284     
285 fail:
286     if (fd >= 0)
287         close(fd);
288
289     return -1;
290 }
291
292 static int send_packet(int fd, int iface, void *packet, size_t packet_len) {
293     struct sockaddr_ll sa;
294     
295     assert(fd >= 0);
296     assert(packet);
297     assert(packet_len > 0);
298
299     memset(&sa, 0, sizeof(sa));
300     sa.sll_family = AF_PACKET;
301     sa.sll_protocol = htons(ETH_P_ARP);
302     sa.sll_ifindex = iface;
303     sa.sll_halen = ETHER_ADDRLEN;
304     memset(sa.sll_addr, 0xFF, ETHER_ADDRLEN);
305
306     if (sendto(fd, packet, packet_len, 0, (struct sockaddr*) &sa, sizeof(sa)) < 0) {
307         daemon_log(LOG_ERR, "sendto() failed: %s", strerror(errno));
308         return -1;
309     }
310
311     return 0;
312 }
313
314 static int recv_packet(int fd, void **packet, size_t *packet_len) {
315     int s;
316     struct sockaddr_ll sa;
317     socklen_t sa_len;
318     
319     assert(fd >= 0);
320     assert(packet);
321     assert(packet_len);
322
323     *packet = NULL;
324
325     if (ioctl(fd, FIONREAD, &s) < 0) {
326         daemon_log(LOG_ERR, "FIONREAD failed: %s", strerror(errno));
327         goto fail;
328     }
329
330     assert(s > 0);
331
332     *packet_len = (size_t) s;
333     *packet = avahi_new(uint8_t, s);
334
335     sa_len = sizeof(sa);
336     if (recvfrom(fd, *packet, s, 0, (struct sockaddr*) &sa, &sa_len) < 0) {
337         daemon_log(LOG_ERR, "recvfrom() failed: %s", strerror(errno));
338         goto fail;
339     }
340     
341     return 0;
342     
343 fail:
344     if (*packet)
345         avahi_free(*packet);
346
347     return -1;
348 }
349  
350 static int is_ll_address(uint32_t addr) {
351     return (ntohl(addr) & IPV4LL_NETMASK) == IPV4LL_NETWORK;
352 }
353
354 static struct timeval *elapse_time(struct timeval *tv, unsigned msec, unsigned jitter) {
355     assert(tv);
356
357     gettimeofday(tv, NULL);
358
359     if (msec)
360         avahi_timeval_add(tv, (AvahiUsec) msec*1000);
361
362     if (jitter)
363         avahi_timeval_add(tv, (AvahiUsec) (jitter*1000.0*rand()/(RAND_MAX+1.0)));
364         
365     return tv;
366 }
367
368 static int loop(int iface, uint32_t addr) {
369     int fd = -1, ret = -1;
370     struct timeval next_wakeup;
371     int next_wakeup_valid = 0;
372     char buf[64];
373     void *in_packet = NULL;
374     size_t in_packet_len;
375     void *out_packet = NULL;
376     size_t out_packet_len;
377     uint8_t hw_address[ETHER_ADDRLEN];
378     struct pollfd pollfds[1];
379
380     enum {
381         EVENT_NULL,
382         EVENT_PACKET,
383         EVENT_TIMEOUT
384     } event = EVENT_NULL;
385     
386     if ((fd = open_socket(iface, hw_address)) < 0)
387         goto fail;
388
389     if (addr && !is_ll_address(addr)) {
390         daemon_log(LOG_WARNING, "Requested address %s is not from IPv4LL range 169.254/16, ignoring.", inet_ntop(AF_INET, &addr, buf, sizeof(buf)));
391         addr = 0;
392     }
393
394     if (!addr) {
395         int i;
396         uint32_t a = 1;
397
398         for (i = 0; i < ETHER_ADDRLEN; i++)
399             a += hw_address[i]*i;
400
401         addr = htonl(IPV4LL_NETWORK | (uint32_t) a);
402     }
403
404     daemon_log(LOG_INFO, "Starting with address %s", inet_ntop(AF_INET, &addr, buf, sizeof(buf)));
405
406     memset(pollfds, 0, sizeof(pollfds));
407     pollfds[0].fd = fd;
408     pollfds[0].events = POLLIN;
409     
410     for (;;) {
411         int r, timeout;
412         AvahiUsec usec;
413
414         if (state == STATE_INVALID) {
415
416             /* First, wait a random time */
417             set_state(STATE_WAITING_PROBE, 1);
418
419             elapse_time(&next_wakeup, 0, PROBE_WAIT*1000);
420             next_wakeup_valid = 1;
421
422         } else if ((state == STATE_WAITING_PROBE && event == EVENT_TIMEOUT) ||
423                    (state == STATE_PROBING && event == EVENT_TIMEOUT && n_iteration < PROBE_NUM-2)) {
424
425             /* Send a probe */
426             out_packet = packet_new_probe(addr, hw_address, &out_packet_len);
427             set_state(STATE_PROBING, 0);
428
429             elapse_time(&next_wakeup, PROBE_MIN*1000, (PROBE_MAX-PROBE_MIN)*1000);
430             next_wakeup_valid = 1;
431             
432         } else if (state == STATE_PROBING && event == EVENT_TIMEOUT && n_iteration >= PROBE_NUM-2) {
433
434             /* Send the last probe */
435             out_packet = packet_new_probe(addr, hw_address, &out_packet_len);
436             set_state(STATE_WAITING_ANNOUNCE, 1);
437
438             elapse_time(&next_wakeup, ANNOUNCE_WAIT*1000, 0);
439             next_wakeup_valid = 1;
440             
441         } else if ((state == STATE_WAITING_ANNOUNCE && event == EVENT_TIMEOUT) ||
442                    (state == STATE_ANNOUNCING && event == EVENT_TIMEOUT && n_iteration < ANNOUNCE_NUM-1)) {
443
444             /* Send announcement packet */
445             out_packet = packet_new_announcement(addr, hw_address, &out_packet_len);
446             set_state(STATE_ANNOUNCING, 0);
447
448             elapse_time(&next_wakeup, ANNOUNCE_INTERVAL*1000, 0);
449             next_wakeup_valid = 1;
450             
451             if (n_iteration == 0) {
452                 add_address(iface, addr);
453                 n_conflict = 0;
454             }
455
456         } else if ((state == STATE_ANNOUNCING && event == EVENT_TIMEOUT && n_iteration >= ANNOUNCE_NUM-1)) {
457
458             daemon_log(LOG_INFO, "Successfully claimed IP address %s", inet_ntop(AF_INET, &addr, buf, sizeof(buf)));
459             set_state(STATE_RUNNING, 0);
460             
461         } else if (event == EVENT_PACKET) {
462             ArpPacketInfo info;
463
464             assert(in_packet);
465             
466             if (packet_parse(in_packet, in_packet_len, &info) < 0)
467                 daemon_log(LOG_WARNING, "Failed to parse incoming ARP packet.");
468             else {
469                 int conflict = 0;
470
471                 if (info.sender_ip_address == addr) {
472                     /* Normal conflict */
473                     conflict = 1;
474                     daemon_log(LOG_INFO, "Recieved conflicting normal ARP packet.");
475                 } else if (state == STATE_WAITING_PROBE || state == STATE_PROBING || state == STATE_WAITING_ANNOUNCE) {
476                     /* Probe conflict */
477                     conflict = info.target_ip_address == addr && memcmp(hw_address, info.sender_hw_address, ETHER_ADDRLEN);
478                     daemon_log(LOG_INFO, "Recieved conflicting probe ARP packet.");
479                 }
480
481                 if (conflict) {
482                     
483                     if (state == STATE_RUNNING || state == STATE_ANNOUNCING)
484                         remove_address(iface, addr);
485                     
486                     /* Pick a new address */
487                     addr = pick_addr(addr);
488
489                     daemon_log(LOG_INFO, "Trying address %s", inet_ntop(AF_INET, &addr, buf, sizeof(buf)));
490
491                     set_state(STATE_WAITING_PROBE, 1);
492
493                     n_conflict++;
494
495                     if (n_conflict >= MAX_CONFLICTS) {
496                         daemon_log(LOG_WARNING, "Got too many conflicts, rate limiting new probes.");
497                         elapse_time(&next_wakeup, RATE_LIMIT_INTERVAL*1000, PROBE_WAIT*1000);
498                     } else
499                         elapse_time(&next_wakeup, 0, PROBE_WAIT*1000);
500
501                     next_wakeup_valid = 1;
502                 } else
503                     daemon_log(LOG_DEBUG, "Ignoring ARP packet.");
504             }
505         }
506         
507         if (out_packet) {
508             daemon_log(LOG_DEBUG, "sending...");
509             
510             if (send_packet(fd, iface, out_packet, out_packet_len) < 0)
511                 goto fail;
512             
513             avahi_free(out_packet);
514             out_packet = NULL;
515         }
516
517         if (in_packet) {
518             avahi_free(in_packet);
519             in_packet = NULL;
520         }
521
522         timeout = -1;
523         
524         if (next_wakeup_valid) {
525             usec = avahi_age(&next_wakeup);
526             timeout = usec < 0 ? (int) (-usec/1000) : 0;
527         }
528
529         daemon_log(LOG_DEBUG, "sleeping %ims", timeout);
530                     
531         while ((r = poll(pollfds, 1, timeout)) < 0 && errno == EINTR)
532             ;
533
534         if (r < 0) {
535             daemon_log(LOG_ERR, "poll() failed: %s", strerror(r));
536             break;
537         } else if (r == 0) {
538             event = EVENT_TIMEOUT;
539             next_wakeup_valid = 0;
540         } else {
541             assert(pollfds[0].revents == POLLIN);
542
543             if (recv_packet(fd, &in_packet, &in_packet_len) < 0)
544                 goto fail;
545
546             if (in_packet)
547                 event = EVENT_PACKET;
548         }
549     }
550
551     ret = 0;
552     
553 fail:
554
555     avahi_free(out_packet);
556     avahi_free(in_packet);
557     
558     if (fd >= 0)
559         close(fd);
560     
561     return ret;
562 }
563
564 static int get_ifindex(const char *name) {
565     int fd = -1;
566     struct ifreq ifreq;
567
568     if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
569         daemon_log(LOG_ERR, "socket() failed: %s", strerror(errno));
570         goto fail;
571     }
572
573     memset(&ifreq, 0, sizeof(ifreq));
574     strncpy(ifreq.ifr_name, name, IFNAMSIZ-1);
575     ifreq.ifr_name[IFNAMSIZ-1] = 0;
576
577     if (ioctl(fd, SIOCGIFINDEX, &ifreq) < 0) {
578         daemon_log(LOG_ERR, "SIOCGIFINDEX failed: %s", strerror(errno));
579         goto fail;
580     }
581
582     return ifreq.ifr_ifindex;
583
584 fail:
585
586     if (fd >= 0)
587         close(fd);
588     
589     return -1;
590 }
591
592 int main(int argc, char*argv[]) {
593     int ret = 1;
594     int ifindex;
595     uint32_t addr = 0;
596
597     init_rand_seed();
598
599     if ((ifindex = get_ifindex(argc >= 2 ? argv[1] : "eth0")) < 0)
600         goto fail;
601
602     if (argc >= 3)
603         addr = inet_addr(argv[2]);
604     
605     if (loop(ifindex, addr) < 0)
606         goto fail;
607     
608     ret = 0;
609
610     
611 fail:
612     
613     return ret;
614 }
615
616 /* TODO:
617
618 - netlink
619 - man page
620 - user script
621 - chroot/drop privs/caps
622 - daemonize
623 - defend
624 - signals
625 - store last used address
626 - cmdline
627
628 */