1 /* 2 * Copyright (c) 1982, 1986, 1991 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * from: @(#)in_pcb.c 7.14 (Berkeley) 4/20/91 34 * $Id: in_pcb.c,v 1.5 1993/06/11 09:12:21 deraadt Exp $ 35 */ 36 37 #include "param.h" 38 #include "systm.h" 39 #include "malloc.h" 40 #include "mbuf.h" 41 #include "protosw.h" 42 #include "socket.h" 43 #include "socketvar.h" 44 #include "ioctl.h" 45 46 #include "../net/if.h" 47 #include "../net/route.h" 48 49 #include "in.h" 50 #include "in_systm.h" 51 #include "ip.h" 52 #include "in_pcb.h" 53 #include "in_var.h" 54 55 struct in_addr zeroin_addr; 56 57 in_pcballoc(so, head) 58 struct socket *so; 59 struct inpcb *head; 60 { 61 struct mbuf *m; 62 register struct inpcb *inp; 63 64 m = m_getclr(M_DONTWAIT, MT_PCB); 65 if (m == NULL) 66 return (ENOBUFS); 67 inp = mtod(m, struct inpcb *); 68 inp->inp_head = head; 69 inp->inp_socket = so; 70 insque(inp, head); 71 so->so_pcb = (caddr_t)inp; 72 return (0); 73 } 74 75 in_pcbbind(inp, nam) 76 register struct inpcb *inp; 77 struct mbuf *nam; 78 { 79 register struct socket *so = inp->inp_socket; 80 register struct inpcb *head = inp->inp_head; 81 register struct sockaddr_in *sin; 82 u_short lport = 0; 83 int wild = 0; 84 85 if (in_ifaddr == 0) 86 return (EADDRNOTAVAIL); 87 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) 88 return (EINVAL); 89 90 if ((so->so_options & SO_REUSEADDR) == 0 && 91 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 92 (so->so_options & SO_ACCEPTCONN) == 0)) 93 wild = INPLOOKUP_WILDCARD; 94 95 if (nam == 0) 96 goto noname; 97 sin = mtod(nam, struct sockaddr_in *); 98 if (nam->m_len != sizeof (*sin)) 99 return (EINVAL); 100 if (sin->sin_addr.s_addr != INADDR_ANY) { 101 int tport = sin->sin_port; 102 103 sin->sin_port = 0; /* yech... */ 104 if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 105 return (EADDRNOTAVAIL); 106 sin->sin_port = tport; 107 } 108 lport = sin->sin_port; 109 if (lport) { 110 u_short aport = ntohs(lport); 111 112 /* GROSS */ 113 if (aport < IPPORT_RESERVED && (so->so_state & SS_PRIV) == 0) 114 return (EACCES); 115 if (in_pcblookup(head, 116 zeroin_addr, 0, sin->sin_addr, lport, wild)) 117 return (EADDRINUSE); 118 } 119 inp->inp_laddr = sin->sin_addr; 120 noname: 121 if (lport == 0) 122 do { 123 if (head->inp_lport++ < IPPORT_RESERVED || 124 head->inp_lport > IPPORT_USERRESERVED) 125 head->inp_lport = IPPORT_RESERVED; 126 lport = htons(head->inp_lport); 127 } while (in_pcblookup(head, 128 zeroin_addr, 0, inp->inp_laddr, lport, wild)); 129 inp->inp_lport = lport; 130 return (0); 131 } 132 133 /* 134 * Connect from a socket to a specified address. 135 * Both address and port must be specified in argument sin. 136 * If don't have a local address for this socket yet, 137 * then pick one. 138 */ 139 in_pcbconnect(inp, nam) 140 register struct inpcb *inp; 141 struct mbuf *nam; 142 { 143 struct in_ifaddr *ia; 144 struct sockaddr_in *ifaddr; 145 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 146 147 if (nam->m_len != sizeof (*sin)) 148 return (EINVAL); 149 if (sin->sin_family != AF_INET) 150 return (EAFNOSUPPORT); 151 if (sin->sin_port == 0) 152 return (EADDRNOTAVAIL); 153 if (in_ifaddr) { 154 /* 155 * If the destination address is INADDR_ANY, 156 * use the primary local address. 157 * If the supplied address is INADDR_BROADCAST, 158 * and the primary interface supports broadcast, 159 * choose the broadcast address for that interface. 160 */ 161 #define satosin(sa) ((struct sockaddr_in *)(sa)) 162 if (sin->sin_addr.s_addr == INADDR_ANY) 163 sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr; 164 else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && 165 (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST)) 166 sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr; 167 } 168 if (inp->inp_laddr.s_addr == INADDR_ANY) { 169 register struct route *ro; 170 struct ifnet *ifp; 171 172 ia = (struct in_ifaddr *)0; 173 /* 174 * If route is known or can be allocated now, 175 * our src addr is taken from the i/f, else punt. 176 */ 177 ro = &inp->inp_route; 178 if (ro->ro_rt && 179 (satosin(&ro->ro_dst)->sin_addr.s_addr != 180 sin->sin_addr.s_addr || 181 inp->inp_socket->so_options & SO_DONTROUTE)) { 182 RTFREE(ro->ro_rt); 183 ro->ro_rt = (struct rtentry *)0; 184 } 185 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 186 (ro->ro_rt == (struct rtentry *)0 || 187 ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 188 /* No route yet, so try to acquire one */ 189 ro->ro_dst.sa_family = AF_INET; 190 ro->ro_dst.sa_len = sizeof(struct sockaddr_in); 191 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 192 sin->sin_addr; 193 rtalloc(ro); 194 } 195 /* 196 * If we found a route, use the address 197 * corresponding to the outgoing interface 198 * unless it is the loopback (in case a route 199 * to our address on another net goes to loopback). 200 */ 201 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) && 202 (ifp->if_flags & IFF_LOOPBACK) == 0) 203 for (ia = in_ifaddr; ia; ia = ia->ia_next) 204 if (ia->ia_ifp == ifp) 205 break; 206 if (ia == 0) { 207 int fport = sin->sin_port; 208 209 sin->sin_port = 0; 210 ia = (struct in_ifaddr *) 211 ifa_ifwithdstaddr((struct sockaddr *)sin); 212 sin->sin_port = fport; 213 if (ia == 0) 214 ia = in_iaonnetof(in_netof(sin->sin_addr)); 215 if (ia == 0) 216 ia = in_ifaddr; 217 if (ia == 0) 218 return (EADDRNOTAVAIL); 219 } 220 ifaddr = (struct sockaddr_in *)&ia->ia_addr; 221 } 222 if (in_pcblookup(inp->inp_head, 223 sin->sin_addr, 224 sin->sin_port, 225 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 226 inp->inp_lport, 227 0)) 228 return (EADDRINUSE); 229 if (inp->inp_laddr.s_addr == INADDR_ANY) { 230 if (inp->inp_lport == 0) 231 (void)in_pcbbind(inp, (struct mbuf *)0); 232 inp->inp_laddr = ifaddr->sin_addr; 233 } 234 inp->inp_faddr = sin->sin_addr; 235 inp->inp_fport = sin->sin_port; 236 return (0); 237 } 238 239 in_pcbdisconnect(inp) 240 struct inpcb *inp; 241 { 242 243 inp->inp_faddr.s_addr = INADDR_ANY; 244 inp->inp_fport = 0; 245 if (inp->inp_socket->so_state & SS_NOFDREF) 246 in_pcbdetach(inp); 247 } 248 249 in_pcbdetach(inp) 250 struct inpcb *inp; 251 { 252 struct socket *so = inp->inp_socket; 253 254 so->so_pcb = 0; 255 sofree(so); 256 if (inp->inp_options) 257 (void)m_free(inp->inp_options); 258 if (inp->inp_route.ro_rt) 259 rtfree(inp->inp_route.ro_rt); 260 remque(inp); 261 (void) m_free(dtom(inp)); 262 } 263 264 in_setsockaddr(inp, nam) 265 register struct inpcb *inp; 266 struct mbuf *nam; 267 { 268 register struct sockaddr_in *sin; 269 270 nam->m_len = sizeof (*sin); 271 sin = mtod(nam, struct sockaddr_in *); 272 bzero((caddr_t)sin, sizeof (*sin)); 273 sin->sin_family = AF_INET; 274 sin->sin_len = sizeof(*sin); 275 sin->sin_port = inp->inp_lport; 276 sin->sin_addr = inp->inp_laddr; 277 } 278 279 in_setpeeraddr(inp, nam) 280 struct inpcb *inp; 281 struct mbuf *nam; 282 { 283 register struct sockaddr_in *sin; 284 285 nam->m_len = sizeof (*sin); 286 sin = mtod(nam, struct sockaddr_in *); 287 bzero((caddr_t)sin, sizeof (*sin)); 288 sin->sin_family = AF_INET; 289 sin->sin_len = sizeof(*sin); 290 sin->sin_port = inp->inp_fport; 291 sin->sin_addr = inp->inp_faddr; 292 } 293 294 /* 295 * Pass some notification to all connections of a protocol 296 * associated with address dst. The local address and/or port numbers 297 * may be specified to limit the search. The "usual action" will be 298 * taken, depending on the ctlinput cmd. The caller must filter any 299 * cmds that are uninteresting (e.g., no error in the map). 300 * Call the protocol specific routine (if any) to report 301 * any errors for each matching socket. 302 * 303 * Must be called at splnet. 304 */ 305 in_pcbnotify(head, dst, fport, laddr, lport, cmd, notify) 306 struct inpcb *head; 307 struct sockaddr *dst; 308 u_short fport, lport; 309 struct in_addr laddr; 310 int cmd, (*notify)(); 311 { 312 register struct inpcb *inp, *oinp; 313 struct in_addr faddr; 314 int errno; 315 int in_rtchange(); 316 extern u_char inetctlerrmap[]; 317 318 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET) 319 return; 320 faddr = ((struct sockaddr_in *)dst)->sin_addr; 321 if (faddr.s_addr == INADDR_ANY) 322 return; 323 324 /* 325 * Redirects go to all references to the destination, 326 * and use in_rtchange to invalidate the route cache. 327 * Dead host indications: notify all references to the destination. 328 * Otherwise, if we have knowledge of the local port and address, 329 * deliver only to that socket. 330 */ 331 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { 332 fport = 0; 333 lport = 0; 334 laddr.s_addr = 0; 335 if (cmd != PRC_HOSTDEAD) 336 notify = in_rtchange; 337 } 338 errno = inetctlerrmap[cmd]; 339 for (inp = head->inp_next; inp != head;) { 340 if (inp->inp_faddr.s_addr != faddr.s_addr || 341 inp->inp_socket == 0 || 342 (lport && inp->inp_lport != lport) || 343 (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) || 344 (fport && inp->inp_fport != fport)) { 345 inp = inp->inp_next; 346 continue; 347 } 348 oinp = inp; 349 inp = inp->inp_next; 350 if (notify) 351 (*notify)(oinp, errno); 352 } 353 } 354 355 /* 356 * Check for alternatives when higher level complains 357 * about service problems. For now, invalidate cached 358 * routing information. If the route was created dynamically 359 * (by a redirect), time to try a default gateway again. 360 */ 361 in_losing(inp) 362 struct inpcb *inp; 363 { 364 register struct rtentry *rt; 365 366 if ((rt = inp->inp_route.ro_rt)) { 367 rt_missmsg(RTM_LOSING, &inp->inp_route.ro_dst, 368 rt->rt_gateway, (struct sockaddr *)rt_mask(rt), 369 (struct sockaddr *)0, rt->rt_flags, 0); 370 if (rt->rt_flags & RTF_DYNAMIC) 371 (void) rtrequest(RTM_DELETE, rt_key(rt), 372 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 373 (struct rtentry **)0); 374 inp->inp_route.ro_rt = 0; 375 rtfree(rt); 376 /* 377 * A new route can be allocated 378 * the next time output is attempted. 379 */ 380 } 381 } 382 383 /* 384 * After a routing change, flush old routing 385 * and allocate a (hopefully) better one. 386 */ 387 in_rtchange(inp) 388 register struct inpcb *inp; 389 { 390 if (inp->inp_route.ro_rt) { 391 rtfree(inp->inp_route.ro_rt); 392 inp->inp_route.ro_rt = 0; 393 /* 394 * A new route can be allocated the next time 395 * output is attempted. 396 */ 397 } 398 } 399 400 struct inpcb * 401 in_pcblookup(head, faddr, fport, laddr, lport, flags) 402 struct inpcb *head; 403 struct in_addr faddr, laddr; 404 u_short fport, lport; 405 int flags; 406 { 407 register struct inpcb *inp, *match = 0; 408 int matchwild = 3, wildcard; 409 410 for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 411 if (inp->inp_lport != lport) 412 continue; 413 wildcard = 0; 414 if (inp->inp_laddr.s_addr != INADDR_ANY) { 415 if (laddr.s_addr == INADDR_ANY) 416 wildcard++; 417 else if (inp->inp_laddr.s_addr != laddr.s_addr) 418 continue; 419 } else { 420 if (laddr.s_addr != INADDR_ANY) 421 wildcard++; 422 } 423 if (inp->inp_faddr.s_addr != INADDR_ANY) { 424 if (faddr.s_addr == INADDR_ANY) 425 wildcard++; 426 else if (inp->inp_faddr.s_addr != faddr.s_addr || 427 inp->inp_fport != fport) 428 continue; 429 } else { 430 if (faddr.s_addr != INADDR_ANY) 431 wildcard++; 432 } 433 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 434 continue; 435 if (wildcard < matchwild) { 436 match = inp; 437 matchwild = wildcard; 438 if (matchwild == 0) 439 break; 440 } 441 } 442 return (match); 443 } 444