|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * Copyright (c) 1982, 1986, 1991, 1993, 1995
24: * The Regents of the University of California. All rights reserved.
25: *
26: * Redistribution and use in source and binary forms, with or without
27: * modification, are permitted provided that the following conditions
28: * are met:
29: * 1. Redistributions of source code must retain the above copyright
30: * notice, this list of conditions and the following disclaimer.
31: * 2. Redistributions in binary form must reproduce the above copyright
32: * notice, this list of conditions and the following disclaimer in the
33: * documentation and/or other materials provided with the distribution.
34: * 3. All advertising materials mentioning features or use of this software
35: * must display the following acknowledgement:
36: * This product includes software developed by the University of
37: * California, Berkeley and its contributors.
38: * 4. Neither the name of the University nor the names of its contributors
39: * may be used to endorse or promote products derived from this software
40: * without specific prior written permission.
41: *
42: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52: * SUCH DAMAGE.
53: *
54: * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95
55: */
56:
57: #include <sys/param.h>
58: #include <sys/systm.h>
59: #include <sys/malloc.h>
60: #include <sys/mbuf.h>
61: #include <sys/protosw.h>
62: #include <sys/socket.h>
63: #include <sys/socketvar.h>
64: #include <sys/proc.h>
65: #include <sys/kernel.h>
66: #include <sys/sysctl.h>
67:
68: #include <machine/limits.h>
69:
70: #if ISFB31
71: #include <vm/vm_zone.h>
72: #else
73: #include <kern/zalloc.h>
74: #endif
75:
76: #include <net/if.h>
77: #include <net/route.h>
78:
79: #include <netinet/in.h>
80: #include <netinet/in_pcb.h>
81: #include <netinet/in_var.h>
82: #include <netinet/ip_var.h>
83:
84: struct in_addr zeroin_addr;
85:
86: static void in_pcbremlists __P((struct inpcb *));
87: static void in_rtchange __P((struct inpcb *, int));
88:
89:
90: /*
91: * These configure the range of local port addresses assigned to
92: * "unspecified" outgoing connections/packets/whatever.
93: */
94: static int ipport_lowfirstauto = IPPORT_RESERVED - 1; /* 1023 */
95: static int ipport_lowlastauto = IPPORT_RESERVEDSTART; /* 600 */
96: static int ipport_firstauto = IPPORT_RESERVED; /* 1024 */
97: static int ipport_lastauto = IPPORT_USERRESERVED; /* 5000 */
98: static int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 49152 */
99: static int ipport_hilastauto = IPPORT_HILASTAUTO; /* 65535 */
100:
101: #define RANGECHK(var, min, max) \
102: if ((var) < (min)) { (var) = (min); } \
103: else if ((var) > (max)) { (var) = (max); }
104:
105:
106: static int
107: sysctl_net_ipport_check SYSCTL_HANDLER_ARGS
108: {
109: int error = sysctl_handle_int(oidp,
110: oidp->oid_arg1, oidp->oid_arg2, req);
111: if (!error) {
112: RANGECHK(ipport_lowfirstauto, 1, IPPORT_RESERVED - 1);
113: RANGECHK(ipport_lowlastauto, 1, IPPORT_RESERVED - 1);
114: RANGECHK(ipport_firstauto, IPPORT_RESERVED, USHRT_MAX);
115: RANGECHK(ipport_lastauto, IPPORT_RESERVED, USHRT_MAX);
116: RANGECHK(ipport_hifirstauto, IPPORT_RESERVED, USHRT_MAX);
117: RANGECHK(ipport_hilastauto, IPPORT_RESERVED, USHRT_MAX);
118: }
119: return error;
120: }
121:
122: #undef RANGECHK
123:
124: SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports");
125:
126: SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW,
127: &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", "");
128: SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW,
129: &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", "");
130: SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW,
131: &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", "");
132: SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW,
133: &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", "");
134: SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW,
135: &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", "");
136: SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hilast, CTLTYPE_INT|CTLFLAG_RW,
137: &ipport_hilastauto, 0, &sysctl_net_ipport_check, "I", "");
138:
139: /*
140: * in_pcb.c: manage the Protocol Control Blocks.
141: *
142: * NOTE: It is assumed that most of these functions will be called at
143: * splnet(). XXX - There are, unfortunately, a few exceptions to this
144: * rule that should be fixed.
145: */
146:
147: /*
148: * Allocate a PCB and associate it with the socket.
149: */
150: int
151: in_pcballoc(so, pcbinfo, p)
152: struct socket *so;
153: struct inpcbinfo *pcbinfo;
154: struct proc *p;
155: {
156: register struct inpcb *inp;
157:
158: inp = (struct inpcb *) zalloc(pcbinfo->ipi_zone);
159: if (inp == NULL)
160: return (ENOBUFS);
161: bzero((caddr_t)inp, sizeof(*inp));
162: inp->inp_gencnt = ++pcbinfo->ipi_gencnt;
163: inp->inp_pcbinfo = pcbinfo;
164: inp->inp_socket = so;
165: LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list);
166: pcbinfo->ipi_count++;
167: so->so_pcb = (caddr_t)inp;
168: return (0);
169: }
170:
171: int
172: in_pcbbind(inp, nam, p)
173: register struct inpcb *inp;
174: struct sockaddr *nam;
175: struct proc *p;
176: {
177: register struct socket *so = inp->inp_socket;
178: u_short *lastport;
179: struct sockaddr_in *sin;
180: struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
181: u_short lport = 0;
182: int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
183: int error;
184:
185: if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */
186: return (EADDRNOTAVAIL);
187: if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
188: return (EINVAL);
189: if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
190: wild = 1;
191: if (nam) {
192: sin = (struct sockaddr_in *)nam;
193: if (nam->sa_len != sizeof (*sin))
194: return (EINVAL);
195: #ifdef notdef
196: /*
197: * We should check the family, but old programs
198: * incorrectly fail to initialize it.
199: */
200: if (sin->sin_family != AF_INET)
201: return (EAFNOSUPPORT);
202: #endif
203: lport = sin->sin_port;
204: if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
205: /*
206: * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
207: * allow complete duplication of binding if
208: * SO_REUSEPORT is set, or if SO_REUSEADDR is set
209: * and a multicast address is bound on both
210: * new and duplicated sockets.
211: */
212: if (so->so_options & SO_REUSEADDR)
213: reuseport = SO_REUSEADDR|SO_REUSEPORT;
214: } else if (sin->sin_addr.s_addr != INADDR_ANY) {
215: sin->sin_port = 0; /* yech... */
216: if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
217: return (EADDRNOTAVAIL);
218: }
219: if (lport) {
220: struct inpcb *t;
221:
222: /* GROSS */
223: if (ntohs(lport) < IPPORT_RESERVED && p &&
224: suser(p->p_ucred, &p->p_acflag))
225: return (EACCES);
226: if (so->so_uid &&
227: !IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
228: t = in_pcblookup_local(inp->inp_pcbinfo,
229: sin->sin_addr, lport, INPLOOKUP_WILDCARD);
230: if (t &&
231: (ntohl(sin->sin_addr.s_addr) != INADDR_ANY ||
232: ntohl(t->inp_laddr.s_addr) != INADDR_ANY ||
233: (t->inp_socket->so_options &
234: SO_REUSEPORT) == 0) &&
235: (so->so_uid != t->inp_socket->so_uid))
236: return (EADDRINUSE);
237: }
238: t = in_pcblookup_local(pcbinfo, sin->sin_addr,
239: lport, wild);
240: if (t && (reuseport & t->inp_socket->so_options) == 0)
241: return (EADDRINUSE);
242: }
243: inp->inp_laddr = sin->sin_addr;
244: }
245: if (lport == 0) {
246: u_short first, last;
247: int count;
248:
249: inp->inp_flags |= INP_ANONPORT;
250:
251: if (inp->inp_flags & INP_HIGHPORT) {
252: first = ipport_hifirstauto; /* sysctl */
253: last = ipport_hilastauto;
254: lastport = &pcbinfo->lasthi;
255: } else if (inp->inp_flags & INP_LOWPORT) {
256: if (p && (error = suser(p->p_ucred, &p->p_acflag)))
257: return error;
258: first = ipport_lowfirstauto; /* 1023 */
259: last = ipport_lowlastauto; /* 600 */
260: lastport = &pcbinfo->lastlow;
261: } else {
262: first = ipport_firstauto; /* sysctl */
263: last = ipport_lastauto;
264: lastport = &pcbinfo->lastport;
265: }
266: /*
267: * Simple check to ensure all ports are not used up causing
268: * a deadlock here.
269: *
270: * We split the two cases (up and down) so that the direction
271: * is not being tested on each round of the loop.
272: */
273: if (first > last) {
274: /*
275: * counting down
276: */
277: count = first - last;
278:
279: do {
280: if (count-- < 0) { /* completely used? */
281: /*
282: * Undo any address bind that may have
283: * occurred above.
284: */
285: inp->inp_laddr.s_addr = INADDR_ANY;
286: return (EAGAIN);
287: }
288: --*lastport;
289: if (*lastport > first || *lastport < last)
290: *lastport = first;
291: lport = htons(*lastport);
292: } while (in_pcblookup_local(pcbinfo,
293: inp->inp_laddr, lport, wild));
294: } else {
295: /*
296: * counting up
297: */
298: count = last - first;
299:
300: do {
301: if (count-- < 0) { /* completely used? */
302: /*
303: * Undo any address bind that may have
304: * occurred above.
305: */
306: inp->inp_laddr.s_addr = INADDR_ANY;
307: return (EAGAIN);
308: }
309: ++*lastport;
310: if (*lastport < first || *lastport > last)
311: *lastport = first;
312: lport = htons(*lastport);
313: } while (in_pcblookup_local(pcbinfo,
314: inp->inp_laddr, lport, wild));
315: }
316: }
317: inp->inp_lport = lport;
318: if (in_pcbinshash(inp) != 0) {
319: inp->inp_laddr.s_addr = INADDR_ANY;
320: inp->inp_lport = 0;
321: return (EAGAIN);
322: }
323: return (0);
324: }
325:
326: /*
327: * Transform old in_pcbconnect() into an inner subroutine for new
328: * in_pcbconnect(): Do some validity-checking on the remote
329: * address (in mbuf 'nam') and then determine local host address
330: * (i.e., which interface) to use to access that remote host.
331: *
332: * This preserves definition of in_pcbconnect(), while supporting a
333: * slightly different version for T/TCP. (This is more than
334: * a bit of a kludge, but cleaning up the internal interfaces would
335: * have forced minor changes in every protocol).
336: */
337:
338: int
339: in_pcbladdr(inp, nam, plocal_sin)
340: register struct inpcb *inp;
341: struct sockaddr *nam;
342: struct sockaddr_in **plocal_sin;
343: {
344: struct in_ifaddr *ia;
345: register struct sockaddr_in *sin = (struct sockaddr_in *)nam;
346:
347: if (nam->sa_len != sizeof (*sin))
348: return (EINVAL);
349: if (sin->sin_family != AF_INET)
350: return (EAFNOSUPPORT);
351: if (sin->sin_port == 0)
352: return (EADDRNOTAVAIL);
353: if (!TAILQ_EMPTY(&in_ifaddrhead)) {
354: /*
355: * If the destination address is INADDR_ANY,
356: * use the primary local address.
357: * If the supplied address is INADDR_BROADCAST,
358: * and the primary interface supports broadcast,
359: * choose the broadcast address for that interface.
360: */
361: #define satosin(sa) ((struct sockaddr_in *)(sa))
362: #define sintosa(sin) ((struct sockaddr *)(sin))
363: #define ifatoia(ifa) ((struct in_ifaddr *)(ifa))
364: if (sin->sin_addr.s_addr == INADDR_ANY)
365: sin->sin_addr = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr;
366: else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
367: (in_ifaddrhead.tqh_first->ia_ifp->if_flags & IFF_BROADCAST))
368: sin->sin_addr = satosin(&in_ifaddrhead.tqh_first->ia_broadaddr)->sin_addr;
369: }
370: if (inp->inp_laddr.s_addr == INADDR_ANY) {
371: register struct route *ro;
372:
373: ia = (struct in_ifaddr *)0;
374: /*
375: * If route is known or can be allocated now,
376: * our src addr is taken from the i/f, else punt.
377: */
378: ro = &inp->inp_route;
379: if (ro->ro_rt &&
380: (satosin(&ro->ro_dst)->sin_addr.s_addr !=
381: sin->sin_addr.s_addr ||
382: inp->inp_socket->so_options & SO_DONTROUTE)) {
383: RTFREE(ro->ro_rt);
384: ro->ro_rt = (struct rtentry *)0;
385: }
386: if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
387: (ro->ro_rt == (struct rtentry *)0 ||
388: ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
389: /* No route yet, so try to acquire one */
390: ro->ro_dst.sa_family = AF_INET;
391: ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
392: ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
393: sin->sin_addr;
394: rtalloc(ro);
395: }
396: /*
397: * If we found a route, use the address
398: * corresponding to the outgoing interface
399: * unless it is the loopback (in case a route
400: * to our address on another net goes to loopback).
401: */
402: if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
403: ia = ifatoia(ro->ro_rt->rt_ifa);
404: if (ia == 0) {
405: u_short fport = sin->sin_port;
406:
407: sin->sin_port = 0;
408: ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
409: if (ia == 0)
410: ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
411: sin->sin_port = fport;
412: if (ia == 0)
413: ia = in_ifaddrhead.tqh_first;
414: if (ia == 0)
415: return (EADDRNOTAVAIL);
416: }
417: /*
418: * If the destination address is multicast and an outgoing
419: * interface has been set as a multicast option, use the
420: * address of that interface as our source address.
421: */
422: if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
423: inp->inp_moptions != NULL) {
424: struct ip_moptions *imo;
425: struct ifnet *ifp;
426:
427: imo = inp->inp_moptions;
428: if (imo->imo_multicast_ifp != NULL) {
429: ifp = imo->imo_multicast_ifp;
430: for (ia = in_ifaddrhead.tqh_first; ia;
431: ia = ia->ia_link.tqe_next)
432: if (ia->ia_ifp == ifp)
433: break;
434: if (ia == 0)
435: return (EADDRNOTAVAIL);
436: }
437: }
438: /*
439: * Don't do pcblookup call here; return interface in plocal_sin
440: * and exit to caller, that will do the lookup.
441: */
442: *plocal_sin = &ia->ia_addr;
443:
444: }
445: return(0);
446: }
447:
448: /*
449: * Outer subroutine:
450: * Connect from a socket to a specified address.
451: * Both address and port must be specified in argument sin.
452: * If don't have a local address for this socket yet,
453: * then pick one.
454: */
455: int
456: in_pcbconnect(inp, nam, p)
457: register struct inpcb *inp;
458: struct sockaddr *nam;
459: struct proc *p;
460: {
461: struct sockaddr_in *ifaddr;
462: register struct sockaddr_in *sin = (struct sockaddr_in *)nam;
463: int error;
464:
465: /*
466: * Call inner routine, to assign local interface address.
467: */
468: if ((error = in_pcbladdr(inp, nam, &ifaddr)) != 0)
469: return(error);
470:
471: if (in_pcblookup_hash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port,
472: inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
473: inp->inp_lport, 0) != NULL) {
474: return (EADDRINUSE);
475: }
476: if (inp->inp_laddr.s_addr == INADDR_ANY) {
477: if (inp->inp_lport == 0)
478: (void)in_pcbbind(inp, (struct sockaddr *)0, p);
479: inp->inp_laddr = ifaddr->sin_addr;
480: }
481: inp->inp_faddr = sin->sin_addr;
482: inp->inp_fport = sin->sin_port;
483: in_pcbrehash(inp);
484: return (0);
485: }
486:
487: void
488: in_pcbdisconnect(inp)
489: struct inpcb *inp;
490: {
491:
492: inp->inp_faddr.s_addr = INADDR_ANY;
493: inp->inp_fport = 0;
494: in_pcbrehash(inp);
495: if (inp->inp_socket->so_state & SS_NOFDREF)
496: in_pcbdetach(inp);
497: }
498:
499: void
500: in_pcbdetach(inp)
501: struct inpcb *inp;
502: {
503: struct socket *so = inp->inp_socket;
504: struct inpcbinfo *ipi = inp->inp_pcbinfo;
505:
506: inp->inp_gencnt = ++ipi->ipi_gencnt;
507: in_pcbremlists(inp);
508: so->so_pcb = 0;
509: sofree(so);
510: if (inp->inp_options)
511: (void)m_free(inp->inp_options);
512: if (inp->inp_route.ro_rt)
513: rtfree(inp->inp_route.ro_rt);
514: ip_freemoptions(inp->inp_moptions);
515: zfree(ipi->ipi_zone, (vm_offset_t) inp);
516: }
517:
518: /*
519: * The calling convention of in_setsockaddr() and in_setpeeraddr() was
520: * modified to match the pru_sockaddr() and pru_peeraddr() entry points
521: * in struct pr_usrreqs, so that protocols can just reference then directly
522: * without the need for a wrapper function. The socket must have a valid
523: * (i.e., non-nil) PCB, but it should be impossible to get an invalid one
524: * except through a kernel programming error, so it is acceptable to panic
525: * (or in this case trap) if the PCB is invalid. (Actually, we don't trap
526: * because there actually /is/ a programming error somewhere... XXX)
527: */
528: int
529: in_setsockaddr(so, nam)
530: struct socket *so;
531: struct sockaddr **nam;
532: {
533: int s;
534: register struct inpcb *inp;
535: register struct sockaddr_in *sin;
536:
537: /*
538: * Do the malloc first in case it blocks.
539: */
540: MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK);
541: bzero(sin, sizeof *sin);
542: sin->sin_family = AF_INET;
543: sin->sin_len = sizeof(*sin);
544:
545: s = splnet();
546: inp = sotoinpcb(so);
547: if (!inp) {
548: splx(s);
549: FREE(sin, M_SONAME);
550: return EINVAL;
551: }
552: sin->sin_port = inp->inp_lport;
553: sin->sin_addr = inp->inp_laddr;
554: splx(s);
555:
556: *nam = (struct sockaddr *)sin;
557: return 0;
558: }
559:
560: int
561: in_setpeeraddr(so, nam)
562: struct socket *so;
563: struct sockaddr **nam;
564: {
565: int s;
566: struct inpcb *inp;
567: register struct sockaddr_in *sin;
568:
569: /*
570: * Do the malloc first in case it blocks.
571: */
572: MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK);
573: bzero((caddr_t)sin, sizeof (*sin));
574: sin->sin_family = AF_INET;
575: sin->sin_len = sizeof(*sin);
576:
577: s = splnet();
578: inp = sotoinpcb(so);
579: if (!inp) {
580: splx(s);
581: FREE(sin, M_SONAME);
582: return EINVAL;
583: }
584: sin->sin_port = inp->inp_fport;
585: sin->sin_addr = inp->inp_faddr;
586: splx(s);
587:
588: *nam = (struct sockaddr *)sin;
589: return 0;
590: }
591:
592: /*
593: * Pass some notification to all connections of a protocol
594: * associated with address dst. The local address and/or port numbers
595: * may be specified to limit the search. The "usual action" will be
596: * taken, depending on the ctlinput cmd. The caller must filter any
597: * cmds that are uninteresting (e.g., no error in the map).
598: * Call the protocol specific routine (if any) to report
599: * any errors for each matching socket.
600: */
601: void
602: in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify)
603: struct inpcbhead *head;
604: struct sockaddr *dst;
605: u_int fport_arg, lport_arg;
606: struct in_addr laddr;
607: int cmd;
608: void (*notify) __P((struct inpcb *, int));
609: {
610: register struct inpcb *inp, *oinp;
611: struct in_addr faddr;
612: u_short fport = fport_arg, lport = lport_arg;
613: int errno, s;
614:
615: if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
616: return;
617: faddr = ((struct sockaddr_in *)dst)->sin_addr;
618: if (faddr.s_addr == INADDR_ANY)
619: return;
620:
621: /*
622: * Redirects go to all references to the destination,
623: * and use in_rtchange to invalidate the route cache.
624: * Dead host indications: notify all references to the destination.
625: * Otherwise, if we have knowledge of the local port and address,
626: * deliver only to that socket.
627: */
628: if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
629: fport = 0;
630: lport = 0;
631: laddr.s_addr = 0;
632: if (cmd != PRC_HOSTDEAD)
633: notify = in_rtchange;
634: }
635: errno = inetctlerrmap[cmd];
636: s = splnet();
637: for (inp = head->lh_first; inp != NULL;) {
638: if (inp->inp_faddr.s_addr != faddr.s_addr ||
639: inp->inp_socket == 0 ||
640: (lport && inp->inp_lport != lport) ||
641: (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
642: (fport && inp->inp_fport != fport)) {
643: inp = inp->inp_list.le_next;
644: continue;
645: }
646: oinp = inp;
647: inp = inp->inp_list.le_next;
648: if (notify)
649: (*notify)(oinp, errno);
650: }
651: splx(s);
652: }
653:
654: /*
655: * Check for alternatives when higher level complains
656: * about service problems. For now, invalidate cached
657: * routing information. If the route was created dynamically
658: * (by a redirect), time to try a default gateway again.
659: */
660: void
661: in_losing(inp)
662: struct inpcb *inp;
663: {
664: register struct rtentry *rt;
665: struct rt_addrinfo info;
666:
667: if ((rt = inp->inp_route.ro_rt)) {
668: inp->inp_route.ro_rt = 0;
669: bzero((caddr_t)&info, sizeof(info));
670: info.rti_info[RTAX_DST] =
671: (struct sockaddr *)&inp->inp_route.ro_dst;
672: info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
673: info.rti_info[RTAX_NETMASK] = rt_mask(rt);
674: rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
675: if (rt->rt_flags & RTF_DYNAMIC)
676: (void) rtrequest(RTM_DELETE, rt_key(rt),
677: rt->rt_gateway, rt_mask(rt), rt->rt_flags,
678: (struct rtentry **)0);
679: else
680: /*
681: * A new route can be allocated
682: * the next time output is attempted.
683: */
684: rtfree(rt);
685: }
686: }
687:
688: /*
689: * After a routing change, flush old routing
690: * and allocate a (hopefully) better one.
691: */
692: static void
693: in_rtchange(inp, errno)
694: register struct inpcb *inp;
695: int errno;
696: {
697: if (inp->inp_route.ro_rt) {
698: rtfree(inp->inp_route.ro_rt);
699: inp->inp_route.ro_rt = 0;
700: /*
701: * A new route can be allocated the next time
702: * output is attempted.
703: */
704: }
705: }
706:
707: /*
708: * Lookup a PCB based on the local address and port.
709: */
710: struct inpcb *
711: in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
712: struct inpcbinfo *pcbinfo;
713: struct in_addr laddr;
714: u_int lport_arg;
715: int wild_okay;
716: {
717: register struct inpcb *inp;
718: int matchwild = 3, wildcard;
719: u_short lport = lport_arg;
720:
721: if (!wild_okay) {
722: struct inpcbhead *head;
723: /*
724: * Look for an unconnected (wildcard foreign addr) PCB that
725: * matches the local address and port we're looking for.
726: */
727: head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
728: for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
729: if (inp->inp_faddr.s_addr == INADDR_ANY &&
730: inp->inp_laddr.s_addr == laddr.s_addr &&
731: inp->inp_lport == lport) {
732: /*
733: * Found.
734: */
735: return (inp);
736: }
737: }
738: /*
739: * Not found.
740: */
741: return (NULL);
742: } else {
743: struct inpcbporthead *porthash;
744: struct inpcbport *phd;
745: struct inpcb *match = NULL;
746: /*
747: * Best fit PCB lookup.
748: *
749: * First see if this local port is in use by looking on the
750: * port hash list.
751: */
752: porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
753: pcbinfo->porthashmask)];
754: for (phd = porthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) {
755: if (phd->phd_port == lport)
756: break;
757: }
758: if (phd != NULL) {
759: /*
760: * Port is in use by one or more PCBs. Look for best
761: * fit.
762: */
763: for (inp = phd->phd_pcblist.lh_first; inp != NULL;
764: inp = inp->inp_portlist.le_next) {
765: wildcard = 0;
766: if (inp->inp_faddr.s_addr != INADDR_ANY)
767: wildcard++;
768: if (inp->inp_laddr.s_addr != INADDR_ANY) {
769: if (laddr.s_addr == INADDR_ANY)
770: wildcard++;
771: else if (inp->inp_laddr.s_addr != laddr.s_addr)
772: continue;
773: } else {
774: if (laddr.s_addr != INADDR_ANY)
775: wildcard++;
776: }
777: if (wildcard < matchwild) {
778: match = inp;
779: matchwild = wildcard;
780: if (matchwild == 0) {
781: break;
782: }
783: }
784: }
785: }
786: return (match);
787: }
788: }
789:
790: /*
791: * Lookup PCB in hash list.
792: */
793: struct inpcb *
794: in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard)
795: struct inpcbinfo *pcbinfo;
796: struct in_addr faddr, laddr;
797: u_int fport_arg, lport_arg;
798: int wildcard;
799: {
800: struct inpcbhead *head;
801: register struct inpcb *inp;
802: u_short fport = fport_arg, lport = lport_arg;
803:
804: /*
805: * We may have found the pcb in the last lookup - check this first.
806: */
807:
808: if ((!IN_MULTICAST(laddr.s_addr)) && (pcbinfo->last_pcb)) {
809: if (faddr.s_addr == pcbinfo->last_pcb->inp_faddr.s_addr &&
810: laddr.s_addr == pcbinfo->last_pcb->inp_laddr.s_addr &&
811: fport_arg == pcbinfo->last_pcb->inp_fport &&
812: lport_arg == pcbinfo->last_pcb->inp_lport) {
813: /*
814: * Found.
815: */
816: return (pcbinfo->last_pcb);
817: }
818:
819: pcbinfo->last_pcb = 0;
820: }
821:
822: /*
823: * First look for an exact match.
824: */
825: head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];
826: for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
827: if (inp->inp_faddr.s_addr == faddr.s_addr &&
828: inp->inp_laddr.s_addr == laddr.s_addr &&
829: inp->inp_fport == fport &&
830: inp->inp_lport == lport) {
831: /*
832: * Found.
833: */
834: return (inp);
835: }
836: }
837: if (wildcard) {
838: struct inpcb *local_wild = NULL;
839:
840: head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
841: for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
842: if (inp->inp_faddr.s_addr == INADDR_ANY &&
843: inp->inp_lport == lport) {
844: if (inp->inp_laddr.s_addr == laddr.s_addr)
845: return (inp);
846: else if (inp->inp_laddr.s_addr == INADDR_ANY)
847: local_wild = inp;
848: }
849: }
850: return (local_wild);
851: }
852:
853: /*
854: * Not found.
855: */
856: return (NULL);
857: }
858:
859: /*
860: * Insert PCB onto various hash lists.
861: */
862: int
863: in_pcbinshash(inp)
864: struct inpcb *inp;
865: {
866: struct inpcbhead *pcbhash;
867: struct inpcbporthead *pcbporthash;
868: struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
869: struct inpcbport *phd;
870:
871: pcbhash = &pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr,
872: inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)];
873:
874: pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport,
875: pcbinfo->porthashmask)];
876:
877: /*
878: * Go through port list and look for a head for this lport.
879: */
880: for (phd = pcbporthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) {
881: if (phd->phd_port == inp->inp_lport)
882: break;
883: }
884: /*
885: * If none exists, malloc one and tack it on.
886: */
887: if (phd == NULL) {
888: MALLOC(phd, struct inpcbport *, sizeof(struct inpcbport), M_PCB, M_NOWAIT);
889: if (phd == NULL) {
890: return (ENOBUFS); /* XXX */
891: }
892: phd->phd_port = inp->inp_lport;
893: LIST_INIT(&phd->phd_pcblist);
894: LIST_INSERT_HEAD(pcbporthash, phd, phd_hash);
895: }
896: inp->inp_phd = phd;
897: LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist);
898: LIST_INSERT_HEAD(pcbhash, inp, inp_hash);
899: return (0);
900: }
901:
902: /*
903: * Move PCB to the proper hash bucket when { faddr, fport } have been
904: * changed. NOTE: This does not handle the case of the lport changing (the
905: * hashed port list would have to be updated as well), so the lport must
906: * not change after in_pcbinshash() has been called.
907: */
908: void
909: in_pcbrehash(inp)
910: struct inpcb *inp;
911: {
912: struct inpcbhead *head;
913:
914: head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr,
915: inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)];
916:
917: if (inp == inp->inp_pcbinfo->last_pcb)
918: inp->inp_pcbinfo->last_pcb = 0;
919:
920: LIST_REMOVE(inp, inp_hash);
921: LIST_INSERT_HEAD(head, inp, inp_hash);
922: }
923:
924: /*
925: * Remove PCB from various lists.
926: */
927: static void
928: in_pcbremlists(inp)
929: struct inpcb *inp;
930: {
931: inp->inp_gencnt = ++inp->inp_pcbinfo->ipi_gencnt;
932: if (inp == inp->inp_pcbinfo->last_pcb)
933: inp->inp_pcbinfo->last_pcb = 0;
934:
935: if (inp->inp_lport) {
936: struct inpcbport *phd = inp->inp_phd;
937:
938: LIST_REMOVE(inp, inp_hash);
939: LIST_REMOVE(inp, inp_portlist);
940: if (phd->phd_pcblist.lh_first == NULL) {
941: LIST_REMOVE(phd, phd_hash);
942: FREE(phd, M_PCB);
943: }
944: }
945:
946: LIST_REMOVE(inp, inp_list);
947: inp->inp_pcbinfo->ipi_count--;
948: }
949:
950: int
951: in_pcb_grab_port __P((struct inpcbinfo *pcbinfo,
952: u_short options,
953: struct in_addr laddr,
954: u_short *lport,
955: struct in_addr faddr,
956: u_short fport,
957: u_int cookie,
958: u_char owner_id))
959: {
960: struct inpcb *pcb;
961: struct sockaddr_in sin;
962: struct proc *p = current_proc();
963: int stat;
964:
965:
966: pcbinfo->nat_dummy_socket.so_pcb = 0;
967: pcbinfo->nat_dummy_socket.so_options = 0;
968: if (*lport) {
969: /* The grabber wants a particular port */
970:
971: if (faddr.s_addr || fport) {
972: /*
973: * This is either the second half of an active connect, or
974: * it's from the acceptance of an incoming connection.
975: */
976: if (laddr.s_addr == 0) {
977: return EINVAL;
978: }
979:
980: if (in_pcblookup_hash(pcbinfo, faddr, fport,
981: laddr, *lport, 0) != NULL) {
982: if (!(IN_MULTICAST(ntohl(laddr.s_addr)))) {
983: return (EADDRINUSE);
984: }
985: }
986:
987: in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p);
988: pcb = sotoinpcb(&pcbinfo->nat_dummy_socket);
989: pcb->inp_lport = *lport;
990: pcb->inp_laddr.s_addr = laddr.s_addr;
991:
992: pcb->inp_faddr = faddr;
993: pcb->inp_fport = fport;
994: in_pcbinshash(pcb);
995: }
996: else {
997: /*
998: * This is either a bind for a passive socket, or it's the
999: * first part of bind-connect sequence (not likely since an
1000: * ephemeral port is usually used in this case). Or, it's
1001: * the result of a connection acceptance when the foreign
1002: * address/port cannot be provided (which requires the SO_REUSEADDR
1003: * flag if laddr is not multicast).
1004: */
1005:
1006: in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p);
1007: pcb = sotoinpcb(&pcbinfo->nat_dummy_socket);
1008:
1009: pcbinfo->nat_dummy_socket.so_options = options;
1010: bzero(&sin, sizeof(struct sockaddr_in));
1011: sin.sin_len = sizeof(struct sockaddr_in);
1012: sin.sin_family = AF_INET;
1013: sin.sin_addr.s_addr = laddr.s_addr;
1014: sin.sin_port = *lport;
1015:
1016: stat = in_pcbbind((struct inpcb *) pcbinfo->nat_dummy_socket.so_pcb,
1017: (struct sockaddr *) &sin, p);
1018: if (stat) {
1019: in_pcbdetach(pcb);
1020: return stat;
1021: }
1022: }
1023: }
1024: else {
1025: /* The grabber wants an ephemeral port */
1026:
1027: in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p);
1028: pcb = sotoinpcb(&pcbinfo->nat_dummy_socket);
1029:
1030: bzero(&sin, sizeof(struct sockaddr_in));
1031: sin.sin_len = sizeof(struct sockaddr_in);
1032: sin.sin_family = AF_INET;
1033: sin.sin_addr.s_addr = laddr.s_addr;
1034: sin.sin_port = 0;
1035:
1036: if (faddr.s_addr || fport) {
1037: /*
1038: * Not sure if this case will be used - could occur when connect
1039: * is called, skipping the bind.
1040: */
1041:
1042: if (laddr.s_addr == 0) {
1043: in_pcbdetach(pcb);
1044: return EINVAL;
1045: }
1046:
1047: stat = in_pcbbind((struct inpcb *) pcbinfo->nat_dummy_socket.so_pcb,
1048: (struct sockaddr *) &sin, p);
1049: if (stat) {
1050: in_pcbdetach(pcb);
1051: return stat;
1052: }
1053:
1054: if (in_pcblookup_hash(pcbinfo, faddr, fport,
1055: pcb->inp_laddr, pcb->inp_lport, 0) != NULL) {
1056: in_pcbdetach(pcb);
1057: return (EADDRINUSE);
1058: }
1059:
1060: pcb->inp_faddr = faddr;
1061: pcb->inp_fport = fport;
1062: in_pcbrehash(pcb);
1063: }
1064: else {
1065: /*
1066: * This is a simple bind of an ephemeral port. The local addr
1067: * may or may not be defined.
1068: */
1069:
1070: stat = in_pcbbind((struct inpcb *) pcbinfo->nat_dummy_socket.so_pcb,
1071: (struct sockaddr *) &sin, p);
1072: if (stat) {
1073: in_pcbdetach(pcb);
1074: return stat;
1075: }
1076: }
1077: *lport = pcb->inp_lport;
1078: }
1079:
1080:
1081: pcb->nat_owner = owner_id;
1082: pcb->nat_cookie = cookie;
1083: pcb->inp_ppcb = (caddr_t) pcbinfo->dummy_cb;
1084: return 0;
1085: }
1086:
1087: int
1088: in_pcb_letgo_port __P((struct inpcbinfo *pcbinfo, struct in_addr laddr, u_short lport,
1089: struct in_addr faddr, u_short fport, u_char owner_id))
1090: {
1091: struct inpcbhead *head;
1092: register struct inpcb *inp;
1093:
1094:
1095: /*
1096: * First look for an exact match.
1097: */
1098: head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];
1099: for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
1100: if (inp->inp_faddr.s_addr == faddr.s_addr &&
1101: inp->inp_laddr.s_addr == laddr.s_addr &&
1102: inp->inp_fport == fport &&
1103: inp->inp_lport == lport &&
1104: inp->nat_owner == owner_id) {
1105: /*
1106: * Found.
1107: */
1108: in_pcbdetach(inp);
1109: return 0;
1110: }
1111: }
1112:
1113: return ENOENT;
1114: }
1115:
1116: u_char
1117: in_pcb_get_owner(struct inpcbinfo *pcbinfo,
1118: struct in_addr laddr, u_short lport,
1119: struct in_addr faddr, u_short fport,
1120: u_int *cookie)
1121:
1122: {
1123: struct inpcb *inp;
1124: u_char owner_id = INPCB_NO_OWNER;
1125: struct inpcbport *phd;
1126: struct inpcbporthead *porthash;
1127:
1128:
1129: if (IN_MULTICAST(laddr.s_addr)) {
1130: /*
1131: * Walk through PCB's looking for registered
1132: * owners.
1133: */
1134:
1135: porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
1136: pcbinfo->porthashmask)];
1137: for (phd = porthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) {
1138: if (phd->phd_port == lport)
1139: break;
1140: }
1141:
1142: if (phd == 0) {
1143: return INPCB_NO_OWNER;
1144: }
1145:
1146: owner_id = INPCB_NO_OWNER;
1147: for (inp = phd->phd_pcblist.lh_first; inp != NULL;
1148: inp = inp->inp_portlist.le_next) {
1149:
1150: if (inp->inp_laddr.s_addr == laddr.s_addr) {
1151: if (inp->nat_owner == 0)
1152: owner_id |= INPCB_OWNED_BY_X;
1153: else
1154: owner_id |= inp->nat_owner;
1155: }
1156: }
1157:
1158: return owner_id;
1159: }
1160: else {
1161: inp = in_pcblookup_hash(pcbinfo, faddr, fport,
1162: laddr, lport, 1);
1163: if (inp) {
1164: if (inp->nat_owner) {
1165: owner_id = inp->nat_owner;
1166: *cookie = inp->nat_cookie;
1167: }
1168: else {
1169: pcbinfo->last_pcb = inp;
1170: owner_id = INPCB_OWNED_BY_X;
1171: }
1172: }
1173: else
1174: owner_id = INPCB_NO_OWNER;
1175:
1176: return owner_id;
1177: }
1178: }
1179:
1180: int
1181: in_pcb_new_share_client(struct inpcbinfo *pcbinfo, u_char *owner_id)
1182: {
1183:
1184: int i;
1185:
1186:
1187: for (i=0; i < INPCB_MAX_IDS; i++) {
1188: if ((pcbinfo->all_owners & (1 << i)) == 0) {
1189: pcbinfo->all_owners |= (1 << i);
1190: *owner_id = (1 << i);
1191: return 0;
1192: }
1193: }
1194:
1195: return ENOSPC;
1196: }
1197:
1198: int
1199: in_pcb_rem_share_client(struct inpcbinfo *pcbinfo, u_char owner_id)
1200: {
1201: struct inpcb *inp;
1202:
1203:
1204: if (pcbinfo->all_owners & owner_id) {
1205: pcbinfo->all_owners &= ~owner_id;
1206: for (inp = pcbinfo->listhead->lh_first; inp != NULL; inp = inp->inp_list.le_next) {
1207: if (inp->nat_owner & owner_id) {
1208: if (inp->nat_owner == owner_id)
1209: /*
1210: * Deallocate the pcb
1211: */
1212: in_pcbdetach(inp);
1213: else
1214: inp->nat_owner &= ~owner_id;
1215: }
1216: }
1217: }
1218: else {
1219: return ENOENT;
1220: }
1221:
1222: return 0;
1223: }
1224:
1225: void in_pcb_nat_init(struct inpcbinfo *pcbinfo, int afamily,
1226: int pfamily, int protocol)
1227: {
1228: bzero(&pcbinfo->nat_dummy_socket, sizeof(struct socket));
1229: pcbinfo->nat_dummy_socket.so_proto = pffindproto(afamily, pfamily, protocol);
1230: pcbinfo->all_owners = 0;
1231: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.