xref: /openbsd-src/sys/netinet/raw_ip.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: raw_ip.c,v 1.24 2001/06/23 16:15:56 fgsch Exp $	*/
2 /*	$NetBSD: raw_ip.c,v 1.25 1996/02/18 18:58:33 christos Exp $	*/
3 
4 /*
5  * Copyright (c) 1982, 1986, 1988, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	@(#)COPYRIGHT	1.1 (NRL) 17 January 1995
37  *
38  * NRL grants permission for redistribution and use in source and binary
39  * forms, with or without modification, of the software and documentation
40  * created at NRL provided that the following conditions are met:
41  *
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  * 3. All advertising materials mentioning features or use of this software
48  *    must display the following acknowledgements:
49  * 	This product includes software developed by the University of
50  * 	California, Berkeley and its contributors.
51  * 	This product includes software developed at the Information
52  * 	Technology Division, US Naval Research Laboratory.
53  * 4. Neither the name of the NRL nor the names of its contributors
54  *    may be used to endorse or promote products derived from this software
55  *    without specific prior written permission.
56  *
57  * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
58  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
59  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
60  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL NRL OR
61  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
62  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
63  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
64  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
65  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
66  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
67  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
68  *
69  * The views and conclusions contained in the software and documentation
70  * are those of the authors and should not be interpreted as representing
71  * official policies, either expressed or implied, of the US Naval
72  * Research Laboratory (NRL).
73  */
74 
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/mbuf.h>
78 #include <sys/socket.h>
79 #include <sys/protosw.h>
80 #include <sys/socketvar.h>
81 
82 #include <net/if.h>
83 #include <net/route.h>
84 
85 #include <netinet/in.h>
86 #include <netinet/in_systm.h>
87 #include <netinet/ip.h>
88 #include <netinet/ip_mroute.h>
89 #include <netinet/ip_var.h>
90 #include <netinet/in_pcb.h>
91 #include <netinet/in_var.h>
92 #include <netinet/ip_icmp.h>
93 
94 struct inpcbtable rawcbtable;
95 
96 /*
97  * Nominal space allocated to a raw ip socket.
98  */
99 #define	RIPSNDQ		8192
100 #define	RIPRCVQ		8192
101 
102 /*
103  * Raw interface to IP protocol.
104  */
105 
106 /*
107  * Initialize raw connection block q.
108  */
109 void
110 rip_init()
111 {
112 
113 	in_pcbinit(&rawcbtable, 1);
114 }
115 
116 struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
117 
118 /*
119  * Setup generic address and protocol structures
120  * for raw_input routine, then pass them along with
121  * mbuf chain.
122  */
123 void
124 #if __STDC__
125 rip_input(struct mbuf *m, ...)
126 #else
127 rip_input(m, va_alist)
128 	struct mbuf *m;
129 	va_dcl
130 #endif
131 {
132 	register struct ip *ip = mtod(m, struct ip *);
133 	register struct inpcb *inp;
134 	struct socket *last = 0;
135 
136 	ripsrc.sin_addr = ip->ip_src;
137 	for (inp = rawcbtable.inpt_queue.cqh_first;
138 	    inp != (struct inpcb *)&rawcbtable.inpt_queue;
139 	    inp = inp->inp_queue.cqe_next) {
140 #ifdef INET6
141 		if (inp->inp_flags & INP_IPV6)
142 			continue;
143 #endif
144 		if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p)
145 			continue;
146 		if (inp->inp_laddr.s_addr &&
147 		    inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
148 			continue;
149 		if (inp->inp_faddr.s_addr &&
150 		    inp->inp_faddr.s_addr != ip->ip_src.s_addr)
151 			continue;
152 		if (last) {
153 			struct mbuf *n;
154 			if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
155 				if (sbappendaddr(&last->so_rcv,
156 				    sintosa(&ripsrc), n,
157 				    (struct mbuf *)0) == 0)
158 					/* should notify about lost packet */
159 					m_freem(n);
160 				else
161 					sorwakeup(last);
162 			}
163 		}
164 		last = inp->inp_socket;
165 	}
166 	if (last) {
167 		if (sbappendaddr(&last->so_rcv, sintosa(&ripsrc), m,
168 		    (struct mbuf *)0) == 0)
169 			m_freem(m);
170 		else
171 			sorwakeup(last);
172 	} else {
173 		if (ip->ip_p != IPPROTO_ICMP)
174 			icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 0, 0);
175 		else
176 			m_freem(m);
177 		ipstat.ips_noproto++;
178 		ipstat.ips_delivered--;
179 	}
180 }
181 
182 /*
183  * Generate IP header and pass packet to ip_output.
184  * Tack on options user may have setup with control call.
185  */
186 int
187 #if __STDC__
188 rip_output(struct mbuf *m, ...)
189 #else
190 rip_output(m, va_alist)
191 	struct mbuf *m;
192 	va_dcl
193 #endif
194 {
195 	struct socket *so;
196 	u_long dst;
197 	register struct ip *ip;
198 	register struct inpcb *inp;
199 	int flags;
200 	va_list ap;
201 
202 	va_start(ap, m);
203 	so = va_arg(ap, struct socket *);
204 	dst = va_arg(ap, u_long);
205 	va_end(ap);
206 
207 	inp = sotoinpcb(so);
208 	flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
209 
210 	/*
211 	 * If the user handed us a complete IP packet, use it.
212 	 * Otherwise, allocate an mbuf for a header and fill it in.
213 	 */
214 	if ((inp->inp_flags & INP_HDRINCL) == 0) {
215 		if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) {
216 			m_freem(m);
217 			return (EMSGSIZE);
218 		}
219 		M_PREPEND(m, sizeof(struct ip), M_WAIT);
220 		ip = mtod(m, struct ip *);
221 		ip->ip_tos = 0;
222 		ip->ip_off = 0;
223 		ip->ip_p = inp->inp_ip.ip_p;
224 		ip->ip_len = m->m_pkthdr.len;
225 		ip->ip_src = inp->inp_laddr;
226 		ip->ip_dst.s_addr = dst;
227 		ip->ip_ttl = MAXTTL;
228 	} else {
229 		if (m->m_pkthdr.len > IP_MAXPACKET) {
230 			m_freem(m);
231 			return (EMSGSIZE);
232 		}
233 		ip = mtod(m, struct ip *);
234 		NTOHS(ip->ip_len);
235 		NTOHS(ip->ip_off);
236 		/*
237 		 * don't allow both user specified and setsockopt options,
238 		 * and don't allow packet length sizes that will crash
239 		 */
240 		if ((ip->ip_hl != (sizeof (*ip) >> 2) && inp->inp_options) ||
241 		    ip->ip_len > m->m_pkthdr.len ||
242 		    ip->ip_len < ip->ip_hl << 2) {
243 			m_freem(m);
244 			return (EINVAL);
245 		}
246 		if (ip->ip_id == 0) {
247 			ip->ip_id = htons(ip_randomid());
248 		}
249 		/* XXX prevent ip_output from overwriting header fields */
250 		flags |= IP_RAWOUTPUT;
251 		ipstat.ips_rawout++;
252 	}
253 #ifdef INET6
254 	/*
255 	 * A thought:  Even though raw IP shouldn't be able to set IPv6
256 	 *             multicast options, if it does, the last parameter to
257 	 *             ip_output should be guarded against v6/v4 problems.
258 	 */
259 #endif
260 	return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
261 	    inp->inp_moptions, inp));
262 }
263 
264 /*
265  * Raw IP socket option processing.
266  */
267 int
268 rip_ctloutput(op, so, level, optname, m)
269 	int op;
270 	struct socket *so;
271 	int level, optname;
272 	struct mbuf **m;
273 {
274 	register struct inpcb *inp = sotoinpcb(so);
275 	register int error;
276 
277 	if (level != IPPROTO_IP) {
278 		if (op == PRCO_SETOPT && *m)
279 			(void) m_free(*m);
280 		return (EINVAL);
281 	}
282 
283 	switch (optname) {
284 
285 	case IP_HDRINCL:
286 		error = 0;
287 		if (op == PRCO_SETOPT) {
288 			if (*m == 0 || (*m)->m_len < sizeof (int))
289 				error = EINVAL;
290 			else if (*mtod(*m, int *))
291 				inp->inp_flags |= INP_HDRINCL;
292 			else
293 				inp->inp_flags &= ~INP_HDRINCL;
294 			if (*m)
295 				(void)m_free(*m);
296 		} else {
297 			*m = m_get(M_WAIT, M_SOOPTS);
298 			(*m)->m_len = sizeof(int);
299 			*mtod(*m, int *) = inp->inp_flags & INP_HDRINCL;
300 		}
301 		return (error);
302 
303 	case MRT_INIT:
304 	case MRT_DONE:
305 	case MRT_ADD_VIF:
306 	case MRT_DEL_VIF:
307 	case MRT_ADD_MFC:
308 	case MRT_DEL_MFC:
309 	case MRT_VERSION:
310 	case MRT_ASSERT:
311 #ifdef MROUTING
312 		switch (op) {
313 		case PRCO_SETOPT:
314 			error = ip_mrouter_set(optname, so, m);
315 			break;
316 		case PRCO_GETOPT:
317 			error = ip_mrouter_get(optname, so, m);
318 			break;
319 		default:
320 			error = EINVAL;
321 			break;
322 		}
323 		return (error);
324 #else
325 		if (op == PRCO_SETOPT && *m)
326 			m_free(*m);
327 		return (EOPNOTSUPP);
328 #endif
329 	}
330 	return (ip_ctloutput(op, so, level, optname, m));
331 }
332 
333 u_long	rip_sendspace = RIPSNDQ;
334 u_long	rip_recvspace = RIPRCVQ;
335 
336 /*ARGSUSED*/
337 int
338 rip_usrreq(so, req, m, nam, control)
339 	register struct socket *so;
340 	int req;
341 	struct mbuf *m, *nam, *control;
342 {
343 	register int error = 0;
344 	register struct inpcb *inp = sotoinpcb(so);
345 #ifdef MROUTING
346 	extern struct socket *ip_mrouter;
347 #endif
348 	if (req == PRU_CONTROL)
349 		return (in_control(so, (u_long)m, (caddr_t)nam,
350 			(struct ifnet *)control));
351 
352 	if (inp == NULL && req != PRU_ATTACH) {
353 		error = EINVAL;
354 		goto release;
355 	}
356 
357 	switch (req) {
358 
359 	case PRU_ATTACH:
360 		if (inp)
361 			panic("rip_attach");
362 		if ((so->so_state & SS_PRIV) == 0) {
363 			error = EACCES;
364 			break;
365 		}
366 		if ((error = soreserve(so, rip_sendspace, rip_recvspace)) ||
367 		    (error = in_pcballoc(so, &rawcbtable)))
368 			break;
369 		inp = (struct inpcb *)so->so_pcb;
370 		inp->inp_ip.ip_p = (long)nam;
371 		break;
372 
373 	case PRU_DISCONNECT:
374 		if ((so->so_state & SS_ISCONNECTED) == 0) {
375 			error = ENOTCONN;
376 			break;
377 		}
378 		/* FALLTHROUGH */
379 	case PRU_ABORT:
380 		soisdisconnected(so);
381 		/* FALLTHROUGH */
382 	case PRU_DETACH:
383 		if (inp == 0)
384 			panic("rip_detach");
385 #ifdef MROUTING
386 		if (so == ip_mrouter)
387 			ip_mrouter_done();
388 #endif
389 		in_pcbdetach(inp);
390 		break;
391 
392 	case PRU_BIND:
393 	    {
394 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
395 
396 		if (nam->m_len != sizeof(*addr)) {
397 			error = EINVAL;
398 			break;
399 		}
400 		if ((ifnet.tqh_first == 0) ||
401 		    ((addr->sin_family != AF_INET) &&
402 		     (addr->sin_family != AF_IMPLINK)) ||
403 		    (addr->sin_addr.s_addr &&
404 		     ifa_ifwithaddr(sintosa(addr)) == 0)) {
405 			error = EADDRNOTAVAIL;
406 			break;
407 		}
408 		inp->inp_laddr = addr->sin_addr;
409 		break;
410 	    }
411 	case PRU_CONNECT:
412 	    {
413 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
414 
415 		if (nam->m_len != sizeof(*addr)) {
416 			error = EINVAL;
417 			break;
418 		}
419 		if (ifnet.tqh_first == 0) {
420 			error = EADDRNOTAVAIL;
421 			break;
422 		}
423 		if ((addr->sin_family != AF_INET) &&
424 		     (addr->sin_family != AF_IMPLINK)) {
425 			error = EAFNOSUPPORT;
426 			break;
427 		}
428 		inp->inp_faddr = addr->sin_addr;
429 		soisconnected(so);
430 		break;
431 	    }
432 
433 	case PRU_CONNECT2:
434 		error = EOPNOTSUPP;
435 		break;
436 
437 	/*
438 	 * Mark the connection as being incapable of further input.
439 	 */
440 	case PRU_SHUTDOWN:
441 		socantsendmore(so);
442 		break;
443 
444 	/*
445 	 * Ship a packet out.  The appropriate raw output
446 	 * routine handles any massaging necessary.
447 	 */
448 	case PRU_SEND:
449 	    {
450 		register u_int32_t dst;
451 
452 		if (so->so_state & SS_ISCONNECTED) {
453 			if (nam) {
454 				error = EISCONN;
455 				break;
456 			}
457 			dst = inp->inp_faddr.s_addr;
458 		} else {
459 			if (nam == NULL) {
460 				error = ENOTCONN;
461 				break;
462 			}
463 			dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
464 		}
465 #ifdef IPSEC
466 		/* XXX Find an IPsec TDB */
467 #endif
468 		error = rip_output(m, so, dst);
469 		m = NULL;
470 		break;
471 	    }
472 
473 	case PRU_SENSE:
474 		/*
475 		 * stat: don't bother with a blocksize.
476 		 */
477 		return (0);
478 
479 	/*
480 	 * Not supported.
481 	 */
482 	case PRU_RCVOOB:
483 	case PRU_RCVD:
484 	case PRU_LISTEN:
485 	case PRU_ACCEPT:
486 	case PRU_SENDOOB:
487 		error = EOPNOTSUPP;
488 		break;
489 
490 	case PRU_SOCKADDR:
491 		in_setsockaddr(inp, nam);
492 		break;
493 
494 	case PRU_PEERADDR:
495 		in_setpeeraddr(inp, nam);
496 		break;
497 
498 	default:
499 		panic("rip_usrreq");
500 	}
501 release:
502 	if (m != NULL)
503 		m_freem(m);
504 	return (error);
505 }
506