GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/relayd/pfe_route.c Lines: 4 108 3.7 %
Date: 2017-11-07 Branches: 1 43 2.3 %

Line Branch Exec Source
1
/*	$OpenBSD: pfe_route.c,v 1.12 2017/05/28 10:39:15 benno Exp $	*/
2
3
/*
4
 * Copyright (c) 2009 - 2011 Reyk Floeter <reyk@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
#include <sys/queue.h>
21
#include <sys/socket.h>
22
23
#include <netinet/in.h>
24
#include <net/route.h>
25
#include <arpa/inet.h>
26
27
#include <limits.h>
28
#include <stdio.h>
29
#include <unistd.h>
30
#include <string.h>
31
#include <errno.h>
32
33
#include "relayd.h"
34
35
struct relay_rtmsg {
36
	struct rt_msghdr	rm_hdr;
37
	union {
38
		struct {
39
			struct sockaddr_in	rm_dst;
40
			struct sockaddr_in	rm_gateway;
41
			struct sockaddr_in	rm_netmask;
42
			struct sockaddr_rtlabel	rm_label;
43
		}		 u4;
44
		struct {
45
			struct sockaddr_in6	rm_dst;
46
			struct sockaddr_in6	rm_gateway;
47
			struct sockaddr_in6	rm_netmask;
48
			struct sockaddr_rtlabel	rm_label;
49
		}		 u6;
50
	}			 rm_u;
51
};
52
53
void
54
init_routes(struct relayd *env)
55
{
56
1924
	u_int	 rtfilter;
57
58
962
	if (!(env->sc_conf.flags & F_NEEDRT))
59
962
		return;
60
61
	if ((env->sc_rtsock = socket(AF_ROUTE, SOCK_RAW, 0)) == -1)
62
		fatal("%s: failed to open routing socket", __func__);
63
64
	rtfilter = ROUTE_FILTER(0);
65
	if (setsockopt(env->sc_rtsock, AF_ROUTE, ROUTE_MSGFILTER,
66
	    &rtfilter, sizeof(rtfilter)) == -1)
67
		fatal("%s: ROUTE_MSGFILTER", __func__);
68
962
}
69
70
void
71
sync_routes(struct relayd *env, struct router *rt)
72
{
73
	struct netroute		*nr;
74
	struct host		*host;
75
	char			 buf[HOST_NAME_MAX+1];
76
	struct ctl_netroute	 crt;
77
78
	if (!(env->sc_conf.flags & F_NEEDRT))
79
		return;
80
81
	TAILQ_FOREACH(nr, &rt->rt_netroutes, nr_entry) {
82
		print_host(&nr->nr_conf.ss, buf, sizeof(buf));
83
		TAILQ_FOREACH(host, &rt->rt_gwtable->hosts, entry) {
84
			if (host->up == HOST_UNKNOWN)
85
				continue;
86
87
			log_debug("%s: "
88
			    "router %s route %s/%d gateway %s %s priority %d",
89
			    __func__,
90
			    rt->rt_conf.name, buf, nr->nr_conf.prefixlen,
91
			    host->conf.name,
92
			    HOST_ISUP(host->up) ? "up" : "down",
93
			    host->conf.priority);
94
95
			crt.up = host->up;
96
			memcpy(&crt.nr, &nr->nr_conf, sizeof(nr->nr_conf));
97
			memcpy(&crt.host, &host->conf, sizeof(host->conf));
98
			memcpy(&crt.rt, &rt->rt_conf, sizeof(rt->rt_conf));
99
100
			proc_compose(env->sc_ps, PROC_PARENT,
101
			    IMSG_RTMSG, &crt, sizeof(crt));
102
		}
103
	}
104
}
105
106
int
107
pfe_route(struct relayd *env, struct ctl_netroute *crt)
108
{
109
	struct relay_rtmsg		 rm;
110
	struct sockaddr_rtlabel		 sr;
111
	struct sockaddr_storage		*gw;
112
	struct sockaddr_in		*s4;
113
	struct sockaddr_in6		*s6;
114
	size_t				 len = 0;
115
	char				*gwname;
116
	int				 i = 0;
117
118
	gw = &crt->host.ss;
119
	gwname = crt->host.name;
120
121
	bzero(&rm, sizeof(rm));
122
	bzero(&sr, sizeof(sr));
123
124
	rm.rm_hdr.rtm_msglen = len;
125
	rm.rm_hdr.rtm_version = RTM_VERSION;
126
	rm.rm_hdr.rtm_type = HOST_ISUP(crt->up) ? RTM_ADD : RTM_DELETE;
127
	rm.rm_hdr.rtm_flags = RTF_STATIC | RTF_GATEWAY | RTF_MPATH;
128
	rm.rm_hdr.rtm_seq = env->sc_rtseq++;
129
	rm.rm_hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
130
	rm.rm_hdr.rtm_tableid = crt->rt.rtable;
131
	rm.rm_hdr.rtm_priority = crt->host.priority;
132
133
	if (strlen(crt->rt.label)) {
134
		rm.rm_hdr.rtm_addrs |= RTA_LABEL;
135
		sr.sr_len = sizeof(sr);
136
		if (snprintf(sr.sr_label, sizeof(sr.sr_label),
137
		    "%s", crt->rt.label) == -1)
138
			goto bad;
139
	}
140
141
	if (crt->nr.ss.ss_family == AF_INET) {
142
		rm.rm_hdr.rtm_msglen = len =
143
		    sizeof(rm.rm_hdr) + sizeof(rm.rm_u.u4);
144
145
		bcopy(&sr, &rm.rm_u.u4.rm_label, sizeof(sr));
146
147
		s4 = &rm.rm_u.u4.rm_dst;
148
		s4->sin_family = AF_INET;
149
		s4->sin_len = sizeof(rm.rm_u.u4.rm_dst);
150
		s4->sin_addr.s_addr =
151
		    ((struct sockaddr_in *)&crt->nr.ss)->sin_addr.s_addr;
152
153
		s4 = &rm.rm_u.u4.rm_gateway;
154
		s4->sin_family = AF_INET;
155
		s4->sin_len = sizeof(rm.rm_u.u4.rm_gateway);
156
		s4->sin_addr.s_addr =
157
		    ((struct sockaddr_in *)gw)->sin_addr.s_addr;
158
159
		rm.rm_hdr.rtm_addrs |= RTA_NETMASK;
160
		s4 = &rm.rm_u.u4.rm_netmask;
161
		s4->sin_family = AF_INET;
162
		s4->sin_len = sizeof(rm.rm_u.u4.rm_netmask);
163
		if (crt->nr.prefixlen)
164
			s4->sin_addr.s_addr =
165
			    htonl(0xffffffff << (32 - crt->nr.prefixlen));
166
		else if (crt->nr.prefixlen < 0)
167
			rm.rm_hdr.rtm_flags |= RTF_HOST;
168
	} else if (crt->nr.ss.ss_family == AF_INET6) {
169
		rm.rm_hdr.rtm_msglen = len =
170
		    sizeof(rm.rm_hdr) + sizeof(rm.rm_u.u6);
171
172
		bcopy(&sr, &rm.rm_u.u6.rm_label, sizeof(sr));
173
174
		s6 = &rm.rm_u.u6.rm_dst;
175
		bcopy(((struct sockaddr_in6 *)&crt->nr.ss),
176
		    s6, sizeof(*s6));
177
		s6->sin6_family = AF_INET6;
178
		s6->sin6_len = sizeof(*s6);
179
180
		s6 = &rm.rm_u.u6.rm_gateway;
181
		bcopy(((struct sockaddr_in6 *)gw), s6, sizeof(*s6));
182
		s6->sin6_family = AF_INET6;
183
		s6->sin6_len = sizeof(*s6);
184
185
		rm.rm_hdr.rtm_addrs |= RTA_NETMASK;
186
		s6 = &rm.rm_u.u6.rm_netmask;
187
		s6->sin6_family = AF_INET6;
188
		s6->sin6_len = sizeof(*s6);
189
		if (crt->nr.prefixlen) {
190
			for (i = 0; i < crt->nr.prefixlen / 8; i++)
191
				s6->sin6_addr.s6_addr[i] = 0xff;
192
			i = crt->nr.prefixlen % 8;
193
			if (i)
194
				s6->sin6_addr.s6_addr[crt->nr.prefixlen
195
				    / 8] = 0xff00 >> i;
196
		} else if (crt->nr.prefixlen < 0)
197
			rm.rm_hdr.rtm_flags |= RTF_HOST;
198
	} else
199
		fatal("%s: invalid address family", __func__);
200
201
 retry:
202
	if (write(env->sc_rtsock, &rm, len) == -1) {
203
		switch (errno) {
204
		case EEXIST:
205
		case ESRCH:
206
			if (rm.rm_hdr.rtm_type == RTM_ADD) {
207
				rm.rm_hdr.rtm_type = RTM_CHANGE;
208
				goto retry;
209
			} else if (rm.rm_hdr.rtm_type == RTM_DELETE) {
210
				/* Ignore */
211
				break;
212
			}
213
			/* FALLTHROUGH */
214
		default:
215
			goto bad;
216
		}
217
	}
218
219
	log_debug("%s: gateway %s %s", __func__, gwname,
220
	    HOST_ISUP(crt->up) ? "added" : "deleted");
221
222
	return (0);
223
224
 bad:
225
	log_debug("%s: failed to %s gateway %s: %d %s", __func__,
226
	    HOST_ISUP(crt->up) ? "add" : "delete", gwname,
227
	    errno, strerror(errno));
228
229
	return (-1);
230
}