From e0808efe65f7e3a18feaf7a71cca261f4100538a Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Fri, 19 Aug 2011 10:05:47 +0800 Subject: [PATCH] inpcb: Don't choose lport which could render same addr/port pair A TCP connect to 127.0.0.1:PORT_A could be successful even if there is no process listening on PORT_A: 127.0.0.1:PORT_A <---> 127.0.0.1:PORT_A The problem here is that PORT_A is chosen as the lport for the socket to be connected to PORT_A, and this actually creates simultaneous connect on 127.0.0.1 but with only one inpcb. Socket connected in this way is useless and could break connect retry for the service listens on the loopback interface. Therefore, we skip the lport if the result will be: (lport == fport && laddr == faddr) NOTE: This still does not guard against explicit local port and address chosen using bind(2) and then calling connect(2) --- sys/netinet/in_pcb.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 49869791c3..2c253788ce 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -585,7 +585,7 @@ in_pcbconn_bind(struct inpcb *inp, const struct sockaddr *nam, struct ucred *cred = NULL; u_short lport = 0; ushort first, last; - int count, error; + int count, error, dup = 0; if (TAILQ_EMPTY(&in_ifaddrheads[mycpuid])) /* XXX broken! */ return (EADDRNOTAVAIL); @@ -633,6 +633,8 @@ in_pcbconn_bind(struct inpcb *inp, const struct sockaddr *nam, last = ipport_lastauto; lastport = &pcbinfo->lastport; } + +again: /* * Simple check to ensure all ports are not used up causing * a deadlock here. @@ -677,6 +679,21 @@ in_pcbconn_bind(struct inpcb *inp, const struct sockaddr *nam, } while (in_pcblookup_addrport(pcbinfo, inp->inp_laddr, lport, sin->sin_addr, sin->sin_port, cred)); } + + /* This could happen on loopback interface */ + if (sin->sin_port == lport && + sin->sin_addr.s_addr == inp->inp_laddr.s_addr) { + if (dup) { + /* + * Duplicate again; give up + */ + inp->inp_laddr.s_addr = INADDR_ANY; + error = EADDRNOTAVAIL; + goto done; + } + dup = 1; + goto again; + } inp->inp_lport = lport; jsin.sin_family = AF_INET; -- 2.41.0