summaryrefslogtreecommitdiffhomepage
path: root/src/odhcpd.h
blob: 2f7dd25291396d6b09f71d7ce17d1d70a088a68e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
/**
 * Copyright (C) 2012-2013 Steven Barth <steven@midlink.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License v2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#pragma once
#include <netinet/in.h>
#include <netinet/icmp6.h>
#include <netinet/ether.h>
#include <stdbool.h>
#include <syslog.h>

#include <libubox/blobmsg.h>
#include <libubox/list.h>
#include <libubox/uloop.h>
#include <libubox/avl.h>
#include <libubox/ustream.h>
#include <libubox/vlist.h>

// RFC 6106 defines this router advertisement option
#define ND_OPT_ROUTE_INFO 24
#define ND_OPT_RECURSIVE_DNS 25
#define ND_OPT_DNS_SEARCH 31

#define INFINITE_VALID(x) ((x) == 0)

#define _unused __attribute__((unused))
#define _packed __attribute__((packed))

#define ALL_IPV6_NODES "ff02::1"
#define ALL_IPV6_ROUTERS "ff02::2"

#define IN6_IS_ADDR_ULA(a) (((a)->s6_addr32[0] & htonl(0xfe000000)) == htonl(0xfc000000))

struct interface;
struct nl_sock;
extern struct vlist_tree leases;
extern struct config config;

struct odhcpd_event {
	struct uloop_fd uloop;
	void (*handle_dgram)(void *addr, void *data, size_t len,
			struct interface *iface, void *dest_addr);
	void (*handle_error)(struct odhcpd_event *e, int error);
	void (*recv_msgs)(struct odhcpd_event *e);
};

typedef	int (*send_reply_cb_t)(const void *buf, size_t len,
			       const struct sockaddr *dest, socklen_t dest_len,
			       void *opaque);

typedef void (*dhcpv6_binding_cb_handler_t)(struct in6_addr *addr, int prefix,
					    uint32_t pref, uint32_t valid,
					    void *arg);

union if_addr {
	struct in_addr in;
	struct in6_addr in6;
};

struct netevent_handler_info {
	struct interface *iface;
	union {
		struct {
			union if_addr dst;
			uint8_t dst_len;
			union if_addr gateway;
		} rt;
		struct {
			union if_addr dst;
			uint16_t state;
			uint8_t flags;
		} neigh;
		struct {
			struct odhcpd_ipaddr *addrs;
			size_t len;
		} addrs_old;
		union if_addr addr;
	};
};

enum netevents {
	NETEV_IFINDEX_CHANGE,
	NETEV_ADDR_ADD,
	NETEV_ADDR_DEL,
	NETEV_ADDRLIST_CHANGE,
	NETEV_ADDR6_ADD,
	NETEV_ADDR6_DEL,
	NETEV_ADDR6LIST_CHANGE,
	NETEV_ROUTE6_ADD,
	NETEV_ROUTE6_DEL,
	NETEV_NEIGH6_ADD,
	NETEV_NEIGH6_DEL,
};

struct netevent_handler {
	struct list_head head;
	void (*cb) (unsigned long event, struct netevent_handler_info *info);
};

struct odhcpd_ipaddr {
	union if_addr addr;
	uint8_t prefix;
	uint32_t preferred;
	uint32_t valid;

	/* ipv6 only */
	uint8_t dprefix;

	/* ipv4 only */
	struct in_addr broadcast;
};

enum odhcpd_mode {
	MODE_DISABLED,
	MODE_SERVER,
	MODE_RELAY,
	MODE_HYBRID
};


enum odhcpd_assignment_flags {
	OAF_TENTATIVE		= (1 << 0),
	OAF_BOUND		= (1 << 1),
	OAF_STATIC		= (1 << 2),
	OAF_BROKEN_HOSTNAME	= (1 << 3),
	OAF_DHCPV4		= (1 << 4),
	OAF_DHCPV6_NA		= (1 << 5),
	OAF_DHCPV6_PD		= (1 << 6),
};

struct config {
	bool legacy;
	bool main_dhcpv4;
	char *dhcp_cb;
	char *dhcp_statefile;
	int log_level;
};


struct lease {
	struct vlist_node node;
	struct list_head assignments;
	uint32_t ipaddr;
	uint32_t hostid;
	struct ether_addr mac;
	uint16_t duid_len;
	uint8_t *duid;
	uint32_t leasetime;
	char *hostname;
};

enum {
	LEASE_ATTR_IP,
	LEASE_ATTR_MAC,
	LEASE_ATTR_DUID,
	LEASE_ATTR_HOSTID,
	LEASE_ATTR_LEASETIME,
	LEASE_ATTR_NAME,
	LEASE_ATTR_MAX
};

struct odhcpd_ref_ip;

struct dhcp_assignment {
	struct list_head head;
	struct list_head lease_list;

	void (*dhcp_free_cb)(struct dhcp_assignment *a);

	struct interface *iface;
	struct lease *lease;

	struct sockaddr_in6 peer;
	time_t valid_until;

#define fr_timer	reconf_timer
	struct uloop_timeout reconf_timer;
#define accept_fr_nonce accept_reconf
	bool accept_reconf;
#define fr_cnt		reconf_cnt
	int reconf_cnt;
	uint8_t key[16];
	struct odhcpd_ref_ip *fr_ip;

	uint32_t addr;
	uint32_t assigned;
	uint32_t iaid;
	uint8_t length; // length == 128 -> IA_NA, length <= 64 -> IA_PD

	struct odhcpd_ipaddr *managed;
	ssize_t managed_size;
	struct ustream_fd managed_sock;

	unsigned int flags;
	uint32_t leasetime;
	char *hostname;
	char *reqopts;
#define hwaddr		mac
	uint8_t mac[6];

	uint16_t clid_len;
	uint8_t clid_data[];
};


struct interface {
	struct avl_node avl;

	int ifindex;
	char *ifname;
	const char *name;

	// IPv6 runtime data
	struct odhcpd_ipaddr *addr6;
	size_t addr6_len;

	// RA runtime data
	struct odhcpd_event router_event;
	struct uloop_timeout timer_rs;
	uint32_t ra_sent;

	// DHCPv6 runtime data
	struct odhcpd_event dhcpv6_event;
	struct list_head ia_assignments;

	// NDP runtime data
	struct odhcpd_event ndp_event;
	int ndp_ping_fd;

	// IPv4 runtime data
	struct odhcpd_ipaddr *addr4;
	size_t addr4_len;

	// DHCPv4 runtime data
	struct odhcpd_event dhcpv4_event;
	struct list_head dhcpv4_assignments;
	struct list_head dhcpv4_fr_ips;

	// Managed PD
	char dhcpv6_pd_manager[128];
	struct in6_addr dhcpv6_pd_cer;

	// Services
	enum odhcpd_mode ra;
	enum odhcpd_mode dhcpv6;
	enum odhcpd_mode ndp;
	enum odhcpd_mode dhcpv4;

	// Config
	bool inuse;
	bool external;
	bool master;
	bool ignore;
	bool always_rewrite_dns;
	bool dns_service;

	// NDP
	int learn_routes;

	// RA
	uint8_t ra_flags;
	bool ra_slaac;
	bool ra_not_onlink;
	bool ra_advrouter;
	bool ra_useleasetime;
	bool ra_dns;
	bool no_dynamic_dhcp;
	uint8_t pio_filter_length;
	struct in6_addr pio_filter_addr;
	int default_router;
	int route_preference;
	int ra_maxinterval;
	int ra_mininterval;
	int ra_lifetime;
	uint32_t ra_reachabletime;
	uint32_t ra_retranstime;
	uint32_t ra_hoplimit;
	int ra_mtu;

	// DHCP
	uint32_t dhcp_leasetime;

	// DHCPv4
	struct in_addr dhcpv4_start;
	struct in_addr dhcpv4_end;
	struct in_addr dhcpv4_start_ip;
	struct in_addr dhcpv4_end_ip;
	struct in_addr dhcpv4_local;
	struct in_addr dhcpv4_bcast;
	struct in_addr dhcpv4_mask;
	struct in_addr *dhcpv4_router;
	size_t dhcpv4_router_cnt;
	struct in_addr *dhcpv4_dns;
	size_t dhcpv4_dns_cnt;
	bool dhcpv4_forcereconf;

	// DNS
	struct in6_addr *dns;
	size_t dns_cnt;
	uint8_t *search;
	size_t search_len;

	// DHCPV6
	void *dhcpv6_raw;
	size_t dhcpv6_raw_len;
	bool dhcpv6_assignall;
	bool dhcpv6_pd;
	bool dhcpv6_na;

	char *upstream;
	size_t upstream_len;

	char *filter_class;
};

extern struct avl_tree interfaces;
extern const struct blobmsg_policy lease_attrs[LEASE_ATTR_MAX];

inline static void free_assignment(struct dhcp_assignment *a)
{
	list_del(&a->head);
	list_del(&a->lease_list);

	if (a->dhcp_free_cb)
		a->dhcp_free_cb(a);

	free(a->hostname);
	free(a->reqopts);
	free(a);
}

inline static struct dhcp_assignment *alloc_assignment(size_t extra_len)
{
	struct dhcp_assignment *a = calloc(1, sizeof(*a) + extra_len);

	if (!a)
		return NULL;

	INIT_LIST_HEAD(&a->head);
	INIT_LIST_HEAD(&a->lease_list);

	return a;
}

// Exported main functions
int odhcpd_register(struct odhcpd_event *event);
int odhcpd_deregister(struct odhcpd_event *event);
void odhcpd_process(struct odhcpd_event *event);

ssize_t odhcpd_send(int socket, struct sockaddr_in6 *dest,
		struct iovec *iov, size_t iov_len,
		const struct interface *iface);
int odhcpd_get_interface_dns_addr(const struct interface *iface,
		struct in6_addr *addr);
int odhcpd_get_interface_config(const char *ifname, const char *what);
int odhcpd_get_mac(const struct interface *iface, uint8_t mac[6]);
struct interface* odhcpd_get_interface_by_index(int ifindex);
int odhcpd_urandom(void *data, size_t len);

void odhcpd_run(void);
time_t odhcpd_time(void);
ssize_t odhcpd_unhexlify(uint8_t *dst, size_t len, const char *src);
void odhcpd_hexlify(char *dst, const uint8_t *src, size_t len);
const char *odhcpd_print_mac(const uint8_t *mac, const size_t len);

int odhcpd_bmemcmp(const void *av, const void *bv, size_t bits);
void odhcpd_bmemcpy(void *av, const void *bv, size_t bits);

int odhcpd_netmask2bitlen(bool v6, void *mask);
bool odhcpd_bitlen2netmask(bool v6, unsigned int bits, void *mask);
bool odhcpd_valid_hostname(const char *name);

int config_parse_interface(void *data, size_t len, const char *iname, bool overwrite);
struct lease *config_find_lease_by_duid(const uint8_t *duid, const uint16_t len);
struct lease *config_find_lease_by_mac(const uint8_t *mac);
struct lease *config_find_lease_by_hostid(const uint32_t hostid);
struct lease *config_find_lease_by_ipaddr(const uint32_t ipaddr);
int set_lease_from_blobmsg(struct blob_attr *ba);

#ifdef WITH_UBUS
int ubus_init(void);
const char* ubus_get_ifname(const char *name);
void ubus_apply_network(void);
bool ubus_has_prefix(const char *name, const char *ifname);
void ubus_bcast_dhcp_event(const char *type, const uint8_t *mac, const size_t mac_len,
		const struct in_addr *addr, const char *name, const char *interface);
#endif

ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *iface,
		const struct sockaddr_in6 *addr, const void *data, const uint8_t *end);
int dhcpv6_ia_init(void);
int dhcpv6_ia_setup_interface(struct interface *iface, bool enable);
void dhcpv6_ia_enum_addrs(struct interface *iface, struct dhcp_assignment *c, time_t now,
				dhcpv6_binding_cb_handler_t func, void *arg);
void dhcpv6_ia_write_statefile(void);

int netlink_add_netevent_handler(struct netevent_handler *hdlr);
ssize_t netlink_get_interface_addrs(const int ifindex, bool v6,
		struct odhcpd_ipaddr **addrs);
int netlink_get_interface_proxy_neigh(int ifindex, const struct in6_addr *addr);
int netlink_setup_route(const struct in6_addr *addr, const int prefixlen,
		const int ifindex, const struct in6_addr *gw,
		const uint32_t metric, const bool add);
int netlink_setup_proxy_neigh(const struct in6_addr *addr,
		const int ifindex, const bool add);
int netlink_setup_addr(struct odhcpd_ipaddr *addr,
		const int ifindex, const bool v6, const bool add);
void netlink_dump_neigh_table(const bool proxy);
void netlink_dump_addr_table(const bool v6);

// Exported module initializers
int netlink_init(void);
int router_init(void);
int dhcpv6_init(void);
int ndp_init(void);
#ifdef DHCPV4_SUPPORT
int dhcpv4_init(void);

int dhcpv4_setup_interface(struct interface *iface, bool enable);
void dhcpv4_handle_msg(void *addr, void *data, size_t len,
		       struct interface *iface, _unused void *dest_addr,
		       send_reply_cb_t send_reply, void *opaque);
#endif
int router_setup_interface(struct interface *iface, bool enable);
int dhcpv6_setup_interface(struct interface *iface, bool enable);
int ndp_setup_interface(struct interface *iface, bool enable);

void odhcpd_reload(void);