Line data Source code
1 : /* $OpenBSD: raw_ip.c,v 1.112 2018/09/13 19:53:58 bluhm 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. Neither the name of the University nor the names of its contributors
17 : * may be used to endorse or promote products derived from this software
18 : * without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 : * SUCH DAMAGE.
31 : *
32 : * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995
33 : *
34 : * NRL grants permission for redistribution and use in source and binary
35 : * forms, with or without modification, of the software and documentation
36 : * created at NRL provided that the following conditions are met:
37 : *
38 : * 1. Redistributions of source code must retain the above copyright
39 : * notice, this list of conditions and the following disclaimer.
40 : * 2. Redistributions in binary form must reproduce the above copyright
41 : * notice, this list of conditions and the following disclaimer in the
42 : * documentation and/or other materials provided with the distribution.
43 : * 3. All advertising materials mentioning features or use of this software
44 : * must display the following acknowledgements:
45 : * This product includes software developed by the University of
46 : * California, Berkeley and its contributors.
47 : * This product includes software developed at the Information
48 : * Technology Division, US Naval Research Laboratory.
49 : * 4. Neither the name of the NRL nor the names of its contributors
50 : * may be used to endorse or promote products derived from this software
51 : * without specific prior written permission.
52 : *
53 : * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
54 : * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
55 : * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
56 : * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
57 : * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
58 : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
59 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
60 : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
61 : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
62 : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63 : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64 : *
65 : * The views and conclusions contained in the software and documentation
66 : * are those of the authors and should not be interpreted as representing
67 : * official policies, either expressed or implied, of the US Naval
68 : * Research Laboratory (NRL).
69 : */
70 :
71 : #include <sys/param.h>
72 : #include <sys/systm.h>
73 : #include <sys/mbuf.h>
74 : #include <sys/socket.h>
75 : #include <sys/protosw.h>
76 : #include <sys/socketvar.h>
77 :
78 : #include <net/if.h>
79 : #include <net/if_var.h>
80 : #include <net/route.h>
81 :
82 : #include <netinet/in.h>
83 : #include <netinet/ip.h>
84 : #include <netinet/ip_mroute.h>
85 : #include <netinet/ip_var.h>
86 : #include <netinet/in_pcb.h>
87 : #include <netinet/in_var.h>
88 : #include <netinet/ip_icmp.h>
89 :
90 : #include <net/pfvar.h>
91 :
92 : #include "pf.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 0 : rip_init(void)
111 : {
112 :
113 0 : in_pcbinit(&rawcbtable, 1);
114 0 : }
115 :
116 : struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
117 :
118 : int
119 0 : rip_input(struct mbuf **mp, int *offp, int proto, int af)
120 : {
121 0 : struct mbuf *m = *mp;
122 0 : struct ip *ip = mtod(m, struct ip *);
123 : struct inpcb *inp, *last = NULL;
124 : struct in_addr *key;
125 0 : struct mbuf *opts = NULL;
126 0 : struct counters_ref ref;
127 : uint64_t *counters;
128 :
129 0 : KASSERT(af == AF_INET);
130 :
131 0 : ripsrc.sin_addr = ip->ip_src;
132 0 : key = &ip->ip_dst;
133 : #if NPF > 0
134 0 : if (m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) {
135 : struct pf_divert *divert;
136 :
137 0 : divert = pf_find_divert(m);
138 0 : KASSERT(divert != NULL);
139 0 : switch (divert->type) {
140 : case PF_DIVERT_TO:
141 0 : key = &divert->addr.v4;
142 0 : break;
143 : case PF_DIVERT_REPLY:
144 : break;
145 : default:
146 0 : panic("%s: unknown divert type %d, mbuf %p, divert %p",
147 : __func__, divert->type, m, divert);
148 : }
149 0 : }
150 : #endif
151 0 : NET_ASSERT_LOCKED();
152 0 : TAILQ_FOREACH(inp, &rawcbtable.inpt_queue, inp_queue) {
153 0 : if (inp->inp_socket->so_state & SS_CANTRCVMORE)
154 : continue;
155 : #ifdef INET6
156 0 : if (inp->inp_flags & INP_IPV6)
157 : continue;
158 : #endif
159 0 : if (rtable_l2(inp->inp_rtableid) !=
160 0 : rtable_l2(m->m_pkthdr.ph_rtableid))
161 : continue;
162 :
163 0 : if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p)
164 : continue;
165 0 : if (inp->inp_laddr.s_addr &&
166 0 : inp->inp_laddr.s_addr != key->s_addr)
167 : continue;
168 0 : if (inp->inp_faddr.s_addr &&
169 0 : inp->inp_faddr.s_addr != ip->ip_src.s_addr)
170 : continue;
171 0 : if (last) {
172 : struct mbuf *n;
173 :
174 0 : if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) != NULL) {
175 0 : if (last->inp_flags & INP_CONTROLOPTS ||
176 0 : last->inp_socket->so_options & SO_TIMESTAMP)
177 0 : ip_savecontrol(last, &opts, ip, n);
178 0 : if (sbappendaddr(last->inp_socket,
179 0 : &last->inp_socket->so_rcv,
180 0 : sintosa(&ripsrc), n, opts) == 0) {
181 : /* should notify about lost packet */
182 0 : m_freem(n);
183 0 : m_freem(opts);
184 0 : } else
185 0 : sorwakeup(last->inp_socket);
186 0 : opts = NULL;
187 0 : }
188 0 : }
189 : last = inp;
190 0 : }
191 0 : if (last) {
192 0 : if (last->inp_flags & INP_CONTROLOPTS ||
193 0 : last->inp_socket->so_options & SO_TIMESTAMP)
194 0 : ip_savecontrol(last, &opts, ip, m);
195 0 : if (sbappendaddr(last->inp_socket, &last->inp_socket->so_rcv,
196 0 : sintosa(&ripsrc), m, opts) == 0) {
197 0 : m_freem(m);
198 0 : m_freem(opts);
199 0 : } else
200 0 : sorwakeup(last->inp_socket);
201 : } else {
202 0 : if (ip->ip_p != IPPROTO_ICMP)
203 0 : icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 0, 0);
204 : else
205 0 : m_freem(m);
206 :
207 0 : counters = counters_enter(&ref, ipcounters);
208 0 : counters[ips_noproto]++;
209 0 : counters[ips_delivered]--;
210 0 : counters_leave(&ref, ipcounters);
211 : }
212 0 : return IPPROTO_DONE;
213 0 : }
214 :
215 : /*
216 : * Generate IP header and pass packet to ip_output.
217 : * Tack on options user may have setup with control call.
218 : */
219 : int
220 0 : rip_output(struct mbuf *m, struct socket *so, struct sockaddr *dstaddr,
221 : struct mbuf *control)
222 : {
223 : struct ip *ip;
224 : struct inpcb *inp;
225 : int flags, error;
226 :
227 0 : inp = sotoinpcb(so);
228 : flags = IP_ALLOWBROADCAST;
229 :
230 : /*
231 : * If the user handed us a complete IP packet, use it.
232 : * Otherwise, allocate an mbuf for a header and fill it in.
233 : */
234 0 : if ((inp->inp_flags & INP_HDRINCL) == 0) {
235 0 : if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) {
236 0 : m_freem(m);
237 0 : return (EMSGSIZE);
238 : }
239 0 : M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
240 0 : if (!m)
241 0 : return (ENOBUFS);
242 0 : ip = mtod(m, struct ip *);
243 0 : ip->ip_tos = inp->inp_ip.ip_tos;
244 0 : ip->ip_off = htons(0);
245 0 : ip->ip_p = inp->inp_ip.ip_p;
246 0 : ip->ip_len = htons(m->m_pkthdr.len);
247 0 : ip->ip_src = inp->inp_laddr;
248 0 : ip->ip_dst = satosin(dstaddr)->sin_addr;
249 0 : ip->ip_ttl = inp->inp_ip.ip_ttl ? inp->inp_ip.ip_ttl : MAXTTL;
250 0 : } else {
251 0 : if (m->m_pkthdr.len > IP_MAXPACKET) {
252 0 : m_freem(m);
253 0 : return (EMSGSIZE);
254 : }
255 0 : if (m->m_pkthdr.len < sizeof(struct ip)) {
256 0 : m_freem(m);
257 0 : return (EINVAL);
258 : }
259 0 : ip = mtod(m, struct ip *);
260 : /*
261 : * don't allow both user specified and setsockopt options,
262 : * and don't allow packet length sizes that will crash
263 : */
264 0 : if ((ip->ip_hl != (sizeof (*ip) >> 2) && inp->inp_options) ||
265 0 : ntohs(ip->ip_len) > m->m_pkthdr.len ||
266 0 : ntohs(ip->ip_len) < ip->ip_hl << 2) {
267 0 : m_freem(m);
268 0 : return (EINVAL);
269 : }
270 0 : if (ip->ip_id == 0) {
271 0 : ip->ip_id = htons(ip_randomid());
272 0 : }
273 : /* XXX prevent ip_output from overwriting header fields */
274 : flags |= IP_RAWOUTPUT;
275 0 : ipstat_inc(ips_rawout);
276 : }
277 : #ifdef INET6
278 : /*
279 : * A thought: Even though raw IP shouldn't be able to set IPv6
280 : * multicast options, if it does, the last parameter to
281 : * ip_output should be guarded against v6/v4 problems.
282 : */
283 : #endif
284 : /* force routing table */
285 0 : m->m_pkthdr.ph_rtableid = inp->inp_rtableid;
286 :
287 : #if NPF > 0
288 0 : if (inp->inp_socket->so_state & SS_ISCONNECTED &&
289 0 : ip->ip_p != IPPROTO_ICMP)
290 0 : pf_mbuf_link_inpcb(m, inp);
291 : #endif
292 :
293 0 : error = ip_output(m, inp->inp_options, &inp->inp_route, flags,
294 0 : inp->inp_moptions, inp, 0);
295 0 : if (error == EACCES) /* translate pf(4) error for userland */
296 : error = EHOSTUNREACH;
297 0 : return (error);
298 0 : }
299 :
300 : /*
301 : * Raw IP socket option processing.
302 : */
303 : int
304 0 : rip_ctloutput(int op, struct socket *so, int level, int optname,
305 : struct mbuf *m)
306 : {
307 0 : struct inpcb *inp = sotoinpcb(so);
308 : int error;
309 :
310 0 : if (level != IPPROTO_IP)
311 0 : return (EINVAL);
312 :
313 0 : switch (optname) {
314 :
315 : case IP_HDRINCL:
316 : error = 0;
317 0 : if (op == PRCO_SETOPT) {
318 0 : if (m == NULL || m->m_len < sizeof (int))
319 0 : error = EINVAL;
320 0 : else if (*mtod(m, int *))
321 0 : inp->inp_flags |= INP_HDRINCL;
322 : else
323 0 : inp->inp_flags &= ~INP_HDRINCL;
324 : } else {
325 0 : m->m_len = sizeof(int);
326 0 : *mtod(m, int *) = inp->inp_flags & INP_HDRINCL;
327 : }
328 0 : return (error);
329 :
330 : case MRT_INIT:
331 : case MRT_DONE:
332 : case MRT_ADD_VIF:
333 : case MRT_DEL_VIF:
334 : case MRT_ADD_MFC:
335 : case MRT_DEL_MFC:
336 : case MRT_VERSION:
337 : case MRT_ASSERT:
338 : case MRT_API_SUPPORT:
339 : case MRT_API_CONFIG:
340 : #ifdef MROUTING
341 0 : switch (op) {
342 : case PRCO_SETOPT:
343 0 : error = ip_mrouter_set(so, optname, m);
344 0 : break;
345 : case PRCO_GETOPT:
346 0 : error = ip_mrouter_get(so, optname, m);
347 0 : break;
348 : default:
349 : error = EINVAL;
350 0 : break;
351 : }
352 0 : return (error);
353 : #else
354 : return (EOPNOTSUPP);
355 : #endif
356 : }
357 0 : return (ip_ctloutput(op, so, level, optname, m));
358 0 : }
359 :
360 : u_long rip_sendspace = RIPSNDQ;
361 : u_long rip_recvspace = RIPRCVQ;
362 :
363 : /*ARGSUSED*/
364 : int
365 0 : rip_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
366 : struct mbuf *control, struct proc *p)
367 : {
368 : struct inpcb *inp;
369 : int error = 0;
370 :
371 0 : if (req == PRU_CONTROL)
372 0 : return (in_control(so, (u_long)m, (caddr_t)nam,
373 0 : (struct ifnet *)control));
374 :
375 0 : soassertlocked(so);
376 :
377 0 : inp = sotoinpcb(so);
378 0 : if (inp == NULL) {
379 : error = EINVAL;
380 0 : goto release;
381 : }
382 :
383 0 : switch (req) {
384 :
385 : case PRU_DISCONNECT:
386 0 : if ((so->so_state & SS_ISCONNECTED) == 0) {
387 : error = ENOTCONN;
388 0 : break;
389 : }
390 : /* FALLTHROUGH */
391 : case PRU_ABORT:
392 0 : soisdisconnected(so);
393 0 : if (inp == NULL)
394 0 : panic("rip_abort");
395 : #ifdef MROUTING
396 0 : if (so == ip_mrouter[inp->inp_rtableid])
397 0 : ip_mrouter_done(so);
398 : #endif
399 0 : in_pcbdetach(inp);
400 0 : break;
401 :
402 : case PRU_BIND:
403 : {
404 0 : struct sockaddr_in *addr;
405 :
406 0 : if ((error = in_nam2sin(nam, &addr)))
407 0 : break;
408 0 : if (!((so->so_options & SO_BINDANY) ||
409 0 : addr->sin_addr.s_addr == INADDR_ANY ||
410 0 : addr->sin_addr.s_addr == INADDR_BROADCAST ||
411 0 : in_broadcast(addr->sin_addr, inp->inp_rtableid) ||
412 0 : ifa_ifwithaddr(sintosa(addr), inp->inp_rtableid))) {
413 : error = EADDRNOTAVAIL;
414 0 : break;
415 : }
416 0 : inp->inp_laddr = addr->sin_addr;
417 0 : break;
418 0 : }
419 : case PRU_CONNECT:
420 : {
421 0 : struct sockaddr_in *addr;
422 :
423 0 : if ((error = in_nam2sin(nam, &addr)))
424 0 : break;
425 0 : inp->inp_faddr = addr->sin_addr;
426 0 : soisconnected(so);
427 0 : break;
428 0 : }
429 :
430 : case PRU_CONNECT2:
431 : error = EOPNOTSUPP;
432 0 : break;
433 :
434 : /*
435 : * Mark the connection as being incapable of further input.
436 : */
437 : case PRU_SHUTDOWN:
438 0 : socantsendmore(so);
439 0 : break;
440 :
441 : /*
442 : * Ship a packet out. The appropriate raw output
443 : * routine handles any massaging necessary.
444 : */
445 : case PRU_SEND:
446 : {
447 0 : struct sockaddr_in dst;
448 :
449 0 : memset(&dst, 0, sizeof(dst));
450 0 : dst.sin_family = AF_INET;
451 0 : dst.sin_len = sizeof(dst);
452 0 : if (so->so_state & SS_ISCONNECTED) {
453 0 : if (nam) {
454 : error = EISCONN;
455 0 : break;
456 : }
457 0 : dst.sin_addr = inp->inp_faddr;
458 0 : } else {
459 0 : struct sockaddr_in *addr;
460 :
461 0 : if (nam == NULL) {
462 : error = ENOTCONN;
463 0 : break;
464 : }
465 0 : if ((error = in_nam2sin(nam, &addr)))
466 0 : break;
467 0 : dst.sin_addr = addr->sin_addr;
468 0 : }
469 : #ifdef IPSEC
470 : /* XXX Find an IPsec TDB */
471 : #endif
472 0 : error = rip_output(m, so, sintosa(&dst), NULL);
473 : m = NULL;
474 0 : break;
475 0 : }
476 :
477 : case PRU_SENSE:
478 : /*
479 : * stat: don't bother with a blocksize.
480 : */
481 0 : return (0);
482 :
483 : /*
484 : * Not supported.
485 : */
486 : case PRU_LISTEN:
487 : case PRU_ACCEPT:
488 : case PRU_SENDOOB:
489 : error = EOPNOTSUPP;
490 0 : break;
491 :
492 : case PRU_RCVD:
493 : case PRU_RCVOOB:
494 0 : return (EOPNOTSUPP); /* do not free mbuf's */
495 :
496 : case PRU_SOCKADDR:
497 0 : in_setsockaddr(inp, nam);
498 0 : break;
499 :
500 : case PRU_PEERADDR:
501 0 : in_setpeeraddr(inp, nam);
502 0 : break;
503 :
504 : default:
505 0 : panic("rip_usrreq");
506 : }
507 : release:
508 0 : m_freem(control);
509 0 : m_freem(m);
510 0 : return (error);
511 0 : }
512 :
513 : int
514 0 : rip_attach(struct socket *so, int proto)
515 : {
516 : struct inpcb *inp;
517 : int error;
518 :
519 0 : if (so->so_pcb)
520 0 : panic("rip_attach");
521 0 : if ((so->so_state & SS_PRIV) == 0)
522 0 : return EACCES;
523 0 : if (proto < 0 || proto >= IPPROTO_MAX)
524 0 : return EPROTONOSUPPORT;
525 :
526 0 : if ((error = soreserve(so, rip_sendspace, rip_recvspace)))
527 0 : return error;
528 0 : NET_ASSERT_LOCKED();
529 0 : if ((error = in_pcballoc(so, &rawcbtable)))
530 0 : return error;
531 0 : inp = sotoinpcb(so);
532 0 : inp->inp_ip.ip_p = proto;
533 0 : return 0;
534 0 : }
535 :
536 : int
537 0 : rip_detach(struct socket *so)
538 : {
539 0 : struct inpcb *inp = sotoinpcb(so);
540 :
541 0 : soassertlocked(so);
542 :
543 0 : if (inp == NULL)
544 0 : return (EINVAL);
545 :
546 : #ifdef MROUTING
547 0 : if (so == ip_mrouter[inp->inp_rtableid])
548 0 : ip_mrouter_done(so);
549 : #endif
550 0 : in_pcbdetach(inp);
551 :
552 0 : return (0);
553 0 : }
|