VirtualBox

Changeset 72283 in vbox


Ignore:
Timestamp:
May 22, 2018 12:10:03 PM (7 years ago)
Author:
vboxsync
Message:

NAT: sobind - rewrite to also always bind UDP sockets as the old code did.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Network/slirp/socket.c

    r71984 r72283  
    173173
    174174
    175 int
    176 sobind(PNATState pData, struct socket *so)
    177 {
    178     bool fSamePorts = !!(pData->i32AliasMode & PKT_ALIAS_SAME_PORTS);
     175/*
     176 * Worker for sobind() below.
     177 */
     178static int
     179sobindto(struct socket *so, uint32_t addr, uint16_t port)
     180{
    179181    struct sockaddr_in self;
    180     int opt;
    181     int binderr;
    182     int ret;
    183 
    184     /* do we need to bind the socket to specific host address/port? */
    185     if (pData->bindIP.s_addr == INADDR_ANY && !fSamePorts)
    186         return 0;
    187 
    188     opt = 1;
    189     setsockopt(so->s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt));
     182    int status;
     183
     184    if (addr == INADDR_ANY && port == 0 && so->so_type != IPPROTO_UDP)
     185    {
     186        /* TCP sockets without constraints don't need to be bound */
     187        Log2(("NAT: sobind: %s guest %RTnaipv4:%d - nothing to do\n",
     188              so->so_type == IPPROTO_UDP ? "udp" : "tcp",
     189              so->so_laddr.s_addr, ntohs(so->so_lport)));
     190        return 0;
     191    }
    190192
    191193    RT_ZERO(self);
     
    194196#endif
    195197    self.sin_family = AF_INET;
    196     self.sin_addr = pData->bindIP;
    197     self.sin_port = fSamePorts ? so->so_lport : 0;
    198 
    199     Log2(("NAT: binding guest %RTnaipv4:%d to host %RTnaipv4:%d\n",
    200           so->so_laddr.s_addr, ntohs(so->so_lport),
    201           self.sin_addr.s_addr, ntohs(self.sin_port)));
    202 
    203     ret = bind(so->s, (struct sockaddr *)&self, sizeof(self));
    204     if (ret == 0)
    205     {
    206         Log2(("NAT: ... bind ok\n"));
    207         return 0;
    208     }
    209 
    210     if (self.sin_port != 0)
    211     {
    212         if (pData->bindIP.s_addr != INADDR_ANY)
    213         {
    214             Log2(("NAT: failed to bind to %RTnaipv4:%d (bindip,sameports),"
    215                   " retrying with random port\n",
    216                   self.sin_addr.s_addr, self.sin_port));
    217 
    218             /*
    219              * don't try to guess why bind() failed, retry without
    220              * requesting the same port port
    221              */
    222             self.sin_port = 0;
    223 
    224             ret = bind(so->s, (struct sockaddr *)&self, sizeof(self));
    225             if (ret == 0)   /* bindIP ok (but port is not the same) */
    226             {
    227                 Log2(("NAT: ... bind ok (without sameports)\n"));
    228                 return 0;
    229             }
    230         }
    231         else
    232         {
    233             Log2(("NAT: failed to bind to 0.0.0.0:%d (sameports),"
    234                   " ignoring sameports\n",
    235                   self.sin_port));
    236 
    237             /* it's ok if we failed to get the same port */
    238             return 0;
    239         }
    240     }
    241 
    242     binderr = errno;
    243 
    244     Log2(("NAT: failed to bind to %RTnaipv4 (bindip)\n",
    245           self.sin_addr.s_addr));
    246 
    247     closesocket(so->s);
    248     so->s = -1;
    249 #ifdef RT_OS_WINDOWS
    250     WSASetLastError(binderr);
    251 #else
    252     errno = binderr;
    253 #endif
    254     return -1;
     198    self.sin_addr.s_addr = addr;
     199    self.sin_port = port;
     200
     201    status = bind(so->s, (struct sockaddr *)&self, sizeof(self));
     202    if (status == 0)
     203    {
     204        Log2(("NAT: sobind: %s guest %RTnaipv4:%d to host %RTnaipv4:%d\n",
     205              so->so_type == IPPROTO_UDP ? "udp" : "tcp",
     206              so->so_laddr.s_addr, ntohs(so->so_lport), addr, ntohs(port)));
     207        return 0;
     208    }
     209
     210    Log2(("NAT: sobind: %s guest %RTnaipv4:%d to host %RTnaipv4:%d error %d%s\n",
     211          so->so_type == IPPROTO_UDP ? "udp" : "tcp",
     212          so->so_laddr.s_addr, ntohs(so->so_lport),
     213          addr, ntohs(port),
     214          errno, port ? " (will retry with random port)" : ""));
     215
     216    if (port) /* retry without */
     217        status = sobindto(so, addr, 0);
     218
     219    if (addr)
     220        return status;
     221    else
     222        return 0;
     223}
     224
     225
     226/*
     227 * Bind the socket to specific host address and/or port if necessary.
     228 * We also always bind udp sockets to force the local port to be
     229 * allocated and known in advance.
     230 */
     231int
     232sobind(PNATState pData, struct socket *so)
     233{
     234    uint32_t addr = pData->bindIP.s_addr; /* may be INADDR_ANY */
     235    bool fSamePorts = !!(pData->i32AliasMode & PKT_ALIAS_SAME_PORTS);
     236    uint16_t port;
     237    int status;
     238
     239    if (fSamePorts)
     240    {
     241        int opt = 1;
     242        setsockopt(so->s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt));
     243        port = so->so_lport;
     244    }
     245    else
     246    {
     247        port = 0;
     248    }
     249
     250    status = sobindto(so, addr, port);
     251    return status;
    255252}
    256253
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette