Merge "Fix SIGSEV on freeing server domains list" into tizen
[platform/upstream/connman.git] / src / acd.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2018  Commend International GmbH. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  */
17
18 /*
19  *  Address Conflict Detection (RFC 5227)
20  *
21  *  based on DHCP client library with GLib integration,
22  *      Copyright (C) 2009-2014  Intel Corporation. All rights reserved.
23  *
24  */
25
26 #include <netinet/if_ether.h>
27 #include <net/if_arp.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <stdio.h>
31 #include <stdarg.h>
32 #include <string.h>
33
34 #include "connman.h"
35 #include <connman/acd.h>
36 #include <connman/log.h>
37 #include <connman/inet.h>
38 #include <connman/dbus.h>
39 #include <glib.h>
40 #include "src/shared/arp.h"
41
42 enum acd_state {
43         ACD_STATE_PROBE,
44         ACD_STATE_ANNOUNCE,
45         ACD_STATE_MONITOR,
46         ACD_STATE_DEFEND,
47 };
48
49 static const char* acd_state_texts[] = {
50         "PROBE",
51         "ANNOUNCE",
52         "MONITOR",
53         "DEFEND"
54 };
55
56 struct acd_host {
57         enum acd_state state;
58         int ifindex;
59         char *interface;
60         uint8_t mac_address[6];
61         uint32_t requested_ip; /* host byte order */
62
63         /* address conflict fields */
64         uint32_t ac_ip; /* host byte order */
65         uint8_t ac_mac[6];
66         gint64 ac_timestamp;
67         bool ac_resolved;
68         const char *path;
69
70         bool listen_on;
71         int listener_sockfd;
72         unsigned int retry_times;
73         unsigned int conflicts;
74         guint timeout;
75         guint listener_watch;
76
77         acd_host_cb_t ipv4_available_cb;
78         gpointer ipv4_available_data;
79         acd_host_cb_t ipv4_lost_cb;
80         gpointer ipv4_lost_data;
81         acd_host_cb_t ipv4_conflict_cb;
82         gpointer ipv4_conflict_data;
83         acd_host_cb_t ipv4_max_conflicts_cb;
84         gpointer ipv4_max_conflicts_data;
85 };
86
87 static int start_listening(struct acd_host *acd);
88 static void stop_listening(struct acd_host *acd);
89 static gboolean acd_listener_event(GIOChannel *channel, GIOCondition condition,
90                                                         gpointer acd_data);
91 static int acd_recv_arp_packet(struct acd_host *acd);
92 static void send_probe_packet(gpointer acd_data);
93 static gboolean acd_probe_timeout(gpointer acd_data);
94 static gboolean send_announce_packet(gpointer acd_data);
95 static gboolean acd_announce_timeout(gpointer acd_data);
96 static gboolean acd_defend_timeout(gpointer acd_data);
97
98 /* for D-Bus property */
99 static void report_conflict(struct acd_host *acd, const struct ether_arp* arp);
100
101 static void debug(struct acd_host *acd, const char *format, ...)
102 {
103         char str[256];
104         va_list ap;
105
106         va_start(ap, format);
107
108         if (vsnprintf(str, sizeof(str), format, ap) > 0)
109                 connman_info("ACD index %d: %s", acd->ifindex, str);
110
111         va_end(ap);
112 }
113
114 void acd_host_free(struct acd_host *acd)
115 {
116         if (!acd)
117                 return;
118
119         g_free(acd->interface);
120         g_free(acd);
121 }
122
123 struct acd_host *acd_host_new(int ifindex, const char *path)
124 {
125         struct acd_host *acd;
126
127         if (ifindex < 0) {
128                 connman_error("Invalid interface index %d", ifindex);
129                 return NULL;
130         }
131
132         acd = g_try_new0(struct acd_host, 1);
133         if (!acd) {
134                 connman_error("Could not allocate ACD data structure");
135                 return NULL;
136         }
137
138         acd->interface = connman_inet_ifname(ifindex);
139         if (!acd->interface) {
140                 connman_error("Interface with index %d is not available", ifindex);
141                 goto error;
142         }
143
144         if (!connman_inet_is_ifup(ifindex)) {
145                 connman_error("Interface with index %d and name %s is down", ifindex,
146                                 acd->interface);
147                 goto error;
148         }
149
150         __connman_inet_get_interface_mac_address(ifindex, acd->mac_address);
151
152         acd->listener_sockfd = -1;
153         acd->listen_on = false;
154         acd->ifindex = ifindex;
155         acd->listener_watch = 0;
156         acd->retry_times = 0;
157
158         acd->ipv4_available_cb = NULL;
159         acd->ipv4_lost_cb = NULL;
160         acd->ipv4_conflict_cb = NULL;
161         acd->ipv4_max_conflicts_cb = NULL;
162
163         acd->ac_ip = 0;
164         memset(acd->ac_mac, 0, sizeof(acd->ac_mac));
165         acd->ac_timestamp = 0;
166         acd->ac_resolved = true;
167         acd->path = path;
168
169         return acd;
170
171 error:
172         acd_host_free(acd);
173         return NULL;
174 }
175
176 static void remove_timeout(struct acd_host *acd)
177 {
178         if (acd->timeout > 0)
179                 g_source_remove(acd->timeout);
180
181         acd->timeout = 0;
182 }
183
184 static int start_listening(struct acd_host *acd)
185 {
186         GIOChannel *listener_channel;
187         int listener_sockfd;
188
189         if (acd->listen_on)
190                 return 0;
191
192         debug(acd, "start listening");
193
194         listener_sockfd = arp_socket(acd->ifindex);
195         if (listener_sockfd < 0)
196                 return -EIO;
197
198         listener_channel = g_io_channel_unix_new(listener_sockfd);
199         if (!listener_channel) {
200                 /* Failed to create listener channel */
201                 close(listener_sockfd);
202                 return -EIO;
203         }
204
205         acd->listen_on = true;
206         acd->listener_sockfd = listener_sockfd;
207
208         g_io_channel_set_close_on_unref(listener_channel, TRUE);
209         acd->listener_watch =
210                         g_io_add_watch_full(listener_channel, G_PRIORITY_HIGH,
211                                 G_IO_IN | G_IO_NVAL | G_IO_ERR | G_IO_HUP,
212                                                 acd_listener_event, acd,
213                                                                 NULL);
214         g_io_channel_unref(listener_channel);
215
216         return 0;
217 }
218
219 static void stop_listening(struct acd_host *acd)
220 {
221         if (!acd->listen_on)
222                 return;
223
224         if (acd->listener_watch > 0)
225                 g_source_remove(acd->listener_watch);
226         acd->listen_on = FALSE;
227         acd->listener_sockfd = -1;
228         acd->listener_watch = 0;
229 }
230
231 static gboolean acd_listener_event(GIOChannel *channel, GIOCondition condition,
232                                                         gpointer acd_data)
233 {
234         struct acd_host *acd = acd_data;
235
236         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
237                 acd->listener_watch = 0;
238                 return FALSE;
239         }
240
241         if (!acd->listen_on)
242                 return FALSE;
243
244         acd_recv_arp_packet(acd);
245
246         return TRUE;
247 }
248
249 static bool is_link_local(uint32_t ip)
250 {
251         return (ip & LINKLOCAL_ADDR) == LINKLOCAL_ADDR;
252 }
253
254 static int acd_recv_arp_packet(struct acd_host *acd)
255 {
256         ssize_t cnt;
257         struct ether_arp arp;
258         uint32_t ip_n; /* network byte order */
259         struct in_addr addr;
260         int source_conflict;
261         int target_conflict;
262         bool probe;
263         char* confltxt;
264         uint8_t* mac;
265         uint8_t* omac;
266
267         memset(&arp, 0, sizeof(arp));
268         cnt = read(acd->listener_sockfd, &arp, sizeof(arp));
269         if (cnt != sizeof(arp))
270                 return -EINVAL;
271
272         if (arp.arp_op != htons(ARPOP_REPLY) &&
273                         arp.arp_op != htons(ARPOP_REQUEST))
274                 return -EINVAL;
275
276         if (memcmp(arp.arp_sha, acd->mac_address, ETH_ALEN) == 0)
277                 return 0;
278
279         ip_n = htonl(acd->requested_ip);
280         source_conflict = !memcmp(arp.arp_spa, &ip_n, sizeof(uint32_t));
281         probe = !memcmp(arp.arp_spa, "\0\0\0\0", sizeof(uint32_t));
282         target_conflict = probe &&
283                 !memcmp(arp.arp_tpa, &ip_n, sizeof(uint32_t));
284
285         if (!source_conflict && !target_conflict)
286                 return 0;
287
288         acd->conflicts++;
289
290         confltxt = target_conflict ? "target" : "source";
291
292         addr.s_addr = ip_n;
293         debug(acd, "IPv4 %d %s conflicts detected for address %s. "
294                         "State=%s", acd->conflicts, confltxt, inet_ntoa(addr),
295                         acd_state_texts[acd->state]);
296         mac = acd->mac_address;
297         omac = arp.arp_sha;
298         debug(acd, "Our MAC: %02x:%02x:%02x:%02x:%02x:%02x"
299                            " other MAC: %02x:%02x:%02x:%02x:%02x:%02x",
300                         mac[0], mac[1], mac[2],mac[3], mac[4], mac[5],
301                         omac[0], omac[1], omac[2],omac[3], omac[4], omac[5]);
302
303         if (acd->state == ACD_STATE_MONITOR) {
304                 if (!source_conflict)
305                         return 0;
306
307                 acd->state = ACD_STATE_DEFEND;
308                 debug(acd, "DEFEND mode conflicts: %d", acd->conflicts);
309                 /* Try to defend with a single announce. */
310                 send_announce_packet(acd);
311                 return 0;
312         } else if (acd->state == ACD_STATE_DEFEND) {
313                 if (!source_conflict)
314                         return 0;
315
316                 debug(acd, "LOST IPv4 address %s", inet_ntoa(addr));
317                 if (!is_link_local(acd->requested_ip))
318                         report_conflict(acd, &arp);
319
320                 if (acd->ipv4_lost_cb)
321                         acd->ipv4_lost_cb(acd, acd->ipv4_lost_data);
322                 return 0;
323         }
324
325         if (acd->conflicts < MAX_CONFLICTS) {
326                 if (!is_link_local(acd->requested_ip))
327                         report_conflict(acd, &arp);
328
329                 acd_host_stop(acd);
330
331                 /* we need a new request_ip */
332                 if (acd->ipv4_conflict_cb)
333                         acd->ipv4_conflict_cb(acd, acd->ipv4_conflict_data);
334         } else {
335                 acd_host_stop(acd);
336
337                 /*
338                  * Here we got a lot of conflicts, RFC3927 and RFC5227 state that we
339                  * have to wait RATE_LIMIT_INTERVAL before retrying.
340                  */
341                 if (acd->ipv4_max_conflicts_cb)
342                         acd->ipv4_max_conflicts_cb(acd, acd->ipv4_max_conflicts_data);
343         }
344
345         return 0;
346 }
347
348 int acd_host_start(struct acd_host *acd, uint32_t ip)
349 {
350         guint timeout;
351         int err;
352
353         remove_timeout(acd);
354
355         err = start_listening(acd);
356         if (err)
357                 return err;
358
359         acd->retry_times = 0;
360         acd->requested_ip = ip;
361
362         /* First wait a random delay to avoid storm of ARP requests on boot */
363         timeout = __connman_util_random_delay_ms(PROBE_WAIT);
364         acd->state = ACD_STATE_PROBE;
365
366         acd->timeout = g_timeout_add_full(G_PRIORITY_HIGH,
367                                                 timeout,
368                                                 acd_probe_timeout,
369                                                 acd,
370                                                 NULL);
371
372         return 0;
373 }
374
375 void acd_host_stop(struct acd_host *acd)
376 {
377         stop_listening(acd);
378
379         remove_timeout(acd);
380
381         if (acd->listener_watch > 0) {
382                 g_source_remove(acd->listener_watch);
383                 acd->listener_watch = 0;
384         }
385
386         acd->state = ACD_STATE_PROBE;
387         acd->retry_times = 0;
388         acd->requested_ip = 0;
389 }
390
391 static void send_probe_packet(gpointer acd_data)
392 {
393         guint timeout;
394         struct acd_host *acd = acd_data;
395
396         debug(acd, "sending ARP probe request");
397         remove_timeout(acd);
398         if (acd->retry_times == 1) {
399                 acd->state = ACD_STATE_PROBE;
400                 start_listening(acd);
401         }
402         arp_send_packet(acd->mac_address, 0,
403                         acd->requested_ip, acd->ifindex);
404
405         if (acd->retry_times < PROBE_NUM) {
406                 /* Add a random timeout in range of PROBE_MIN to PROBE_MAX. */
407                 timeout = __connman_util_random_delay_ms(PROBE_MAX-PROBE_MIN);
408                 timeout += PROBE_MIN * 1000;
409         } else
410                 timeout = ANNOUNCE_WAIT * 1000;
411
412         acd->timeout = g_timeout_add_full(G_PRIORITY_HIGH,
413                                                  timeout,
414                                                  acd_probe_timeout,
415                                                  acd,
416                                                  NULL);
417 }
418
419 static gboolean acd_probe_timeout(gpointer acd_data)
420 {
421         struct acd_host *acd = acd_data;
422
423         acd->timeout = 0;
424
425         debug(acd, "acd probe timeout (retries %d)", acd->retry_times);
426         if (acd->retry_times == PROBE_NUM) {
427                 acd->state = ACD_STATE_ANNOUNCE;
428                 acd->retry_times = 1;
429
430                 send_announce_packet(acd);
431                 return FALSE;
432         }
433
434         acd->retry_times++;
435         send_probe_packet(acd);
436
437         return FALSE;
438 }
439
440 static gboolean send_announce_packet(gpointer acd_data)
441 {
442         struct acd_host *acd = acd_data;
443
444         debug(acd, "sending ACD announce request");
445
446         arp_send_packet(acd->mac_address,
447                                 acd->requested_ip,
448                                 acd->requested_ip,
449                                 acd->ifindex);
450
451         remove_timeout(acd);
452
453         if (acd->state == ACD_STATE_DEFEND)
454                 acd->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
455                                                 DEFEND_INTERVAL,
456                                                 acd_defend_timeout,
457                                                 acd,
458                                                 NULL);
459         else
460                 acd->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
461                                                 ANNOUNCE_INTERVAL,
462                                                 acd_announce_timeout,
463                                                 acd,
464                                                 NULL);
465         return TRUE;
466 }
467
468 static gboolean acd_announce_timeout(gpointer acd_data)
469 {
470         struct acd_host *acd = acd_data;
471
472         acd->timeout = 0;
473
474         debug(acd, "acd announce timeout (retries %d)", acd->retry_times);
475         if (acd->retry_times != ANNOUNCE_NUM) {
476                 acd->retry_times++;
477                 send_announce_packet(acd);
478                 return FALSE;
479         }
480
481         debug(acd, "switching to monitor mode");
482         acd->state = ACD_STATE_MONITOR;
483
484         if (!acd->ac_resolved && !is_link_local(acd->requested_ip))
485                 report_conflict(acd, NULL);
486
487         if (acd->ipv4_available_cb)
488                 acd->ipv4_available_cb(acd,
489                                         acd->ipv4_available_data);
490         acd->conflicts = 0;
491
492         return FALSE;
493 }
494
495 static gboolean acd_defend_timeout(gpointer acd_data)
496 {
497         struct acd_host *acd = acd_data;
498
499         debug(acd, "back to MONITOR mode");
500         acd->timeout = 0;
501         acd->conflicts = 0;
502         acd->state = ACD_STATE_MONITOR;
503
504         return FALSE;
505 }
506
507 void acd_host_register_event(struct acd_host *acd,
508                             enum acd_host_event event,
509                             acd_host_cb_t func,
510                             gpointer user_data)
511 {
512         switch (event) {
513         case ACD_HOST_EVENT_IPV4_AVAILABLE:
514                 acd->ipv4_available_cb = func;
515                 acd->ipv4_available_data = user_data;
516                 break;
517         case ACD_HOST_EVENT_IPV4_LOST:
518                 acd->ipv4_lost_cb = func;
519                 acd->ipv4_lost_data = user_data;
520                 break;
521         case ACD_HOST_EVENT_IPV4_CONFLICT:
522                 acd->ipv4_conflict_cb = func;
523                 acd->ipv4_conflict_data = user_data;
524                 break;
525         case ACD_HOST_EVENT_IPV4_MAXCONFLICT:
526                 acd->ipv4_max_conflicts_cb = func;
527                 acd->ipv4_max_conflicts_data = user_data;
528                 break;
529         default:
530                 connman_warn("%s unknown event %d.", __FUNCTION__, event);
531                 break;
532         }
533 }
534
535 static void append_ac_mac(DBusMessageIter *iter, void *user_data)
536 {
537         struct acd_host *acd = user_data;
538         char mac[32];
539         uint8_t *m = acd->ac_mac;
540         const char *str = mac;
541
542         snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
543                         m[0], m[1], m[2], m[3], m[4], m[5]);
544         connman_dbus_dict_append_basic(iter, "Address", DBUS_TYPE_STRING, &str);
545 }
546
547 static void append_ac_ipv4(DBusMessageIter *iter, void *user_data)
548 {
549         struct acd_host *acd = user_data;
550         struct in_addr addr;
551         char *a;
552
553         addr.s_addr = htonl(acd->ac_ip);
554         a = inet_ntoa(addr);
555         if (!a)
556                 a = "";
557         connman_dbus_dict_append_basic(iter, "Address", DBUS_TYPE_STRING, &a);
558 }
559
560 static void append_ac_property(DBusMessageIter *iter, void *user_data)
561 {
562         struct acd_host *acd = user_data;
563
564         connman_dbus_dict_append_dict(iter, "IPv4", append_ac_ipv4, acd);
565         connman_dbus_dict_append_dict(iter, "Ethernet", append_ac_mac, acd);
566         connman_dbus_dict_append_basic(iter, "Timestamp", DBUS_TYPE_INT64,
567                         &acd->ac_timestamp);
568         connman_dbus_dict_append_basic(iter, "Resolved", DBUS_TYPE_BOOLEAN,
569                         &acd->ac_resolved);
570 }
571
572 void acd_host_append_dbus_property(struct acd_host *acd, DBusMessageIter *dict)
573 {
574         connman_dbus_dict_append_dict(dict, "LastAddressConflict",
575                         append_ac_property, acd);
576 }
577
578 static void report_conflict(struct acd_host *acd, const struct ether_arp* arp)
579 {
580         if (arp) {
581                 acd->ac_ip = acd->requested_ip;
582                 memcpy(acd->ac_mac, arp->arp_sha, sizeof(acd->ac_mac));
583                 acd->ac_timestamp = g_get_real_time();
584                 acd->ac_resolved = false;
585         } else {
586                 acd->ac_resolved = true;
587         }
588
589         connman_dbus_property_changed_dict(acd->path, CONNMAN_SERVICE_INTERFACE,
590                         "LastAddressConflict", append_ac_property, acd);
591 }
592
593 unsigned int acd_host_get_conflicts_count(struct acd_host *acd)
594 {
595         return acd->conflicts;
596 }