GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/npppd/npppd/../common/recvfromto.c Lines: 0 87 0.0 %
Date: 2017-11-07 Branches: 0 40 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: recvfromto.c,v 1.6 2015/12/17 08:01:55 tb Exp $ */
2
/* adapted from ipsec-tools 0.6 src/racoon/sockmisc.c */
3
/*
4
 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 * 3. Neither the name of the project nor the names of its contributors
16
 *    may be used to endorse or promote products derived from this software
17
 *    without specific prior written permission.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 */
31
#include <sys/types.h>
32
#include <sys/socket.h>
33
#include <sys/uio.h>
34
#include <netinet/in.h>
35
#include <string.h>
36
37
#include "recvfromto.h"
38
39
/*
40
 * Receive packet, with src/dst information.  It is assumed that necessary
41
 * setsockopt() have already performed on socket.
42
 */
43
int
44
recvfromto_nat_t(s, buf, buflen, flags, from, fromlen, to, tolen,
45
    ipsec, ipseclen)
46
	int s;
47
	void *buf;
48
	size_t buflen;
49
	int flags;
50
	struct sockaddr *from;
51
	u_int *fromlen;
52
	struct sockaddr *to;
53
	u_int *tolen;
54
	void *ipsec;
55
	u_int *ipseclen;
56
{
57
	int otolen;
58
	u_int oipseclen = 0;
59
	ssize_t len;
60
	struct sockaddr_storage ss;
61
	struct msghdr m;
62
	struct cmsghdr *cm;
63
	struct iovec iov[2];
64
	u_char cmsgbuf[256];
65
	struct in6_pktinfo *pi;
66
	struct sockaddr_in *sin4;
67
	socklen_t sslen;
68
	struct sockaddr_in6 *sin6;
69
70
	sslen = sizeof(ss);
71
	if (getsockname(s, (struct sockaddr *)&ss, &sslen) < 0)
72
		return -1;
73
74
	m.msg_name = (caddr_t)from;
75
	m.msg_namelen = *fromlen;
76
	iov[0].iov_base = (caddr_t)buf;
77
	iov[0].iov_len = buflen;
78
	m.msg_iov = iov;
79
	m.msg_iovlen = 1;
80
	memset(cmsgbuf, 0, sizeof(cmsgbuf));
81
	cm = (struct cmsghdr *)cmsgbuf;
82
	m.msg_control = (caddr_t)cm;
83
	m.msg_controllen = sizeof(cmsgbuf);
84
	if ((len = recvmsg(s, &m, flags)) <= 0) {
85
		return len;
86
	}
87
	*fromlen = m.msg_namelen;
88
89
	if (ipsec && ipseclen) {
90
		oipseclen = *ipseclen;
91
		*ipseclen = 0;
92
	}
93
	otolen = *tolen;
94
	*tolen = 0;
95
	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
96
	     m.msg_controllen != 0 && cm;
97
	     cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
98
		if (ss.ss_family == AF_INET6
99
		 && cm->cmsg_level == IPPROTO_IPV6
100
		 && cm->cmsg_type == IPV6_PKTINFO
101
		 && otolen >= sizeof(*sin6)) {
102
			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
103
			*tolen = sizeof(*sin6);
104
			sin6 = (struct sockaddr_in6 *)to;
105
			memset(sin6, 0, sizeof(*sin6));
106
			sin6->sin6_family = AF_INET6;
107
#ifndef __linux__
108
			sin6->sin6_len = sizeof(*sin6);
109
#endif
110
			memcpy(&sin6->sin6_addr, &pi->ipi6_addr,
111
				sizeof(sin6->sin6_addr));
112
			/* XXX other cases, such as site-local? */
113
			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
114
				sin6->sin6_scope_id = pi->ipi6_ifindex;
115
			else
116
				sin6->sin6_scope_id = 0;
117
			sin6->sin6_port =
118
				((struct sockaddr_in6 *)&ss)->sin6_port;
119
			otolen = -1;	/* "to" already set */
120
			continue;
121
		}
122
#ifdef IP_IPSECFLOWINFO
123
		if (ss.ss_family == AF_INET	/* ?? */
124
		 && cm->cmsg_level == IPPROTO_IP
125
		 && cm->cmsg_type == IP_IPSECFLOWINFO
126
		 && oipseclen >= sizeof(u_int32_t)) {
127
			*ipseclen = sizeof(u_int32_t);
128
			memcpy(ipsec, CMSG_DATA(cm), *ipseclen);
129
			continue;
130
		}
131
#endif
132
#ifdef __linux__
133
		if (ss.ss_family == AF_INET
134
		 && cm->cmsg_level == IPPROTO_IP
135
		 && cm->cmsg_type == IP_PKTINFO
136
		 && otolen >= sizeof(sin4)) {
137
			struct in_pktinfo *pi = (struct in_pktinfo *)(CMSG_DATA(cm));
138
			*tolen = sizeof(*sin4);
139
			sin4 = (struct sockaddr_in *)to;
140
			memset(sin4, 0, sizeof(*sin4));
141
			sin4->sin_family = AF_INET;
142
			memcpy(&sin4->sin_addr, &pi->ipi_addr,
143
				sizeof(sin4->sin_addr));
144
			sin4->sin_port =
145
				((struct sockaddr_in *)&ss)->sin_port;
146
			otolen = -1;	/* "to" already set */
147
			continue;
148
		}
149
#endif
150
#ifdef IPV6_RECVDSTADDR
151
		if (ss.ss_family == AF_INET6
152
		      && cm->cmsg_level == IPPROTO_IPV6
153
		      && cm->cmsg_type == IPV6_RECVDSTADDR
154
		      && otolen >= sizeof(*sin6)) {
155
			*tolen = sizeof(*sin6);
156
			sin6 = (struct sockaddr_in6 *)to;
157
			memset(sin6, 0, sizeof(*sin6));
158
			sin6->sin6_family = AF_INET6;
159
			sin6->sin6_len = sizeof(*sin6);
160
			memcpy(&sin6->sin6_addr, CMSG_DATA(cm),
161
				sizeof(sin6->sin6_addr));
162
			sin6->sin6_port =
163
				((struct sockaddr_in6 *)&ss)->sin6_port;
164
			otolen = -1;	/* "to" already set */
165
			continue;
166
		}
167
#endif
168
#ifndef __linux__
169
		if (ss.ss_family == AF_INET
170
		 && cm->cmsg_level == IPPROTO_IP
171
		 && cm->cmsg_type == IP_RECVDSTADDR
172
		 && otolen >= sizeof(*sin4)) {
173
			*tolen = sizeof(*sin4);
174
			sin4 = (struct sockaddr_in *)to;
175
			memset(sin4, 0, sizeof(*sin4));
176
			sin4->sin_family = AF_INET;
177
			sin4->sin_len = sizeof(*sin4);
178
			memcpy(&sin4->sin_addr, CMSG_DATA(cm),
179
				sizeof(sin4->sin_addr));
180
			sin4->sin_port = ((struct sockaddr_in *)&ss)->sin_port;
181
			otolen = -1;	/* "to" already set */
182
			continue;
183
		}
184
#endif
185
	}
186
187
	return len;
188
}
189
190
int
191
recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen)
192
	int s;
193
	void *buf;
194
	size_t buflen;
195
	int flags;
196
	struct sockaddr *from;
197
	u_int *fromlen;
198
	struct sockaddr *to;
199
	u_int *tolen;
200
{
201
	return recvfromto_nat_t(s, buf, buflen, flags, from, fromlen,
202
	    to, tolen, NULL, NULL);
203
}
204
205
int
206
sendto_nat_t(s, buf, buflen, flags, to, tolen, ipsec)
207
	int s;
208
	const void *buf;
209
	size_t buflen;
210
	int flags;
211
	struct sockaddr *to;
212
	u_int tolen;
213
	void *ipsec;
214
{
215
#ifdef IP_IPSECFLOWINFO
216
	if (ipsec) {
217
		struct iovec iov[1];
218
		struct msghdr msg;
219
		struct cmsghdr  *cmsg;
220
		union {
221
			struct cmsghdr  hdr;
222
			char            buf[CMSG_SPACE(sizeof(u_int32_t))];
223
		} cmsgbuf;
224
225
		iov[0].iov_base = (char *)buf;
226
		iov[0].iov_len = buflen;
227
		memset(&msg, 0, sizeof(msg));
228
		memset(&cmsgbuf, 0, sizeof(cmsgbuf));
229
		msg.msg_name = to;
230
		msg.msg_namelen = tolen;
231
		msg.msg_iov = iov;
232
		msg.msg_iovlen = 1;
233
		msg.msg_control = (caddr_t)&cmsgbuf.buf;
234
		msg.msg_controllen = sizeof(cmsgbuf.buf);
235
		cmsg = CMSG_FIRSTHDR(&msg);
236
		cmsg->cmsg_len = CMSG_LEN(sizeof(u_int32_t));
237
		cmsg->cmsg_level = IPPROTO_IP;
238
		cmsg->cmsg_type = IP_IPSECFLOWINFO;
239
		memcpy(CMSG_DATA(cmsg), ipsec, sizeof(u_int32_t));
240
		return sendmsg(s, &msg, flags);
241
	}
242
#endif
243
	return sendto(s, buf, buflen, flags, to, tolen);
244
}