1 /*
2 * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2004, 2008, 2009, 2010, 2011,
3 * 2012, 2013
4 * Inferno Nettverk A/S, Norway. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. The above copyright notice, this list of conditions and the following
10 * disclaimer must appear in all copies of the software, derivative works
11 * or modified versions, and any portions thereof, aswell as in all
12 * supporting documentation.
13 * 2. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by
16 * Inferno Nettverk A/S, Norway.
17 * 3. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Inferno Nettverk A/S requests users of this software to return to
32 *
33 * Software Distribution Coordinator or sdc@inet.no
34 * Inferno Nettverk A/S
35 * Oslo Research Park
36 * Gaustadall�en 21
37 * NO-0349 Oslo
38 * Norway
39 *
40 * any improvements or extensions that they make and grant Inferno Nettverk A/S
41 * the rights to redistribute these changes.
42 *
43 */
44
45 #include "common.h"
46
47 #include "upnp.h"
48
49 static const char rcsid[] =
50 "$Id: Rgetsockname.c,v 1.93 2013/10/27 15:24:42 karls Exp $";
51
52 int
Rgetsockname(s,name,namelen)53 Rgetsockname(s, name, namelen)
54 int s;
55 struct sockaddr *name;
56 socklen_t *namelen;
57 {
58 const char *function = "Rgetsockname()";
59 socksfd_t socksfd;
60 struct sockaddr_storage addr;
61
62 clientinit();
63
64 slog(LOG_DEBUG, "%s, fd %d", function, s);
65
66 if (!socks_addrisours(s, &socksfd, 1)) {
67 socks_rmaddr(s, 1);
68 return getsockname(s, name, namelen);
69 }
70
71 if (socksfd.state.version == PROXY_UPNP) {
72 #if HAVE_LIBMINIUPNP
73 if (ADDRISBOUND(&socksfd.remote))
74 addr = socksfd.remote; /* already have it. */
75 else {
76 proxystate_t *state = &socksfd.route->gw.state.data;
77 socksfd_t *p;
78 char straddr[INET_ADDRSTRLEN], emsg[1024];
79 int rc;
80
81 p = socks_getaddr(s, &socksfd, 1);
82 SASSERTX(p != NULL);
83
84 if (socks_initupnp(&socksfd.route->gw, emsg, sizeof(emsg)) != 0) {
85 swarnx("%s: socks_initupnp() failed to init upnp device: %s",
86 function, emsg);
87
88 errno = EOPNOTSUPP;
89 return -1;
90 }
91
92 if ((rc = UPNP_GetExternalIPAddress(state->upnp.controlurl,
93 state->upnp.servicetype,
94 straddr)) != UPNPCOMMAND_SUCCESS) {
95 swarnx("%s: failed to get external ip address of upnp device: %s",
96 function, strupnperror(rc));
97
98 errno = EOPNOTSUPP;
99 return -1;
100 }
101
102 slog(LOG_INFO, "%s: upnp control point's external ip address is %s",
103 function, straddr);
104
105 if (socks_inet_pton(AF_INET,
106 straddr,
107 &TOIN(&socksfd.remote)->sin_addr,
108 NULL) == 1)
109 SET_SOCKADDR(TOSS(&socksfd.remote), AF_INET);
110 else if (socks_inet_pton(AF_INET6,
111 straddr,
112 &TOIN(&socksfd.remote)->sin_addr,
113 &TOIN6(&socksfd.remote)->sin6_scope_id) == 1)
114 SET_SOCKADDR(TOSS(&socksfd.remote), AF_INET6);
115 else {
116 swarn("%s: could not convert string %s to network address",
117 function, straddr);
118
119 return -1;
120 }
121
122 addr = socksfd.remote;
123 socks_addaddr(s, &socksfd, 1);
124 }
125 #else
126 SERRX(socksfd.state.version);
127 #endif /* HAVE_LIBMINIUPNP */
128 }
129 else {
130 switch (socksfd.state.command) {
131 case SOCKS_CONNECT: {
132 sigset_t set, oset;
133
134 /* for non-blocking connect, we get a SIGIO upon completion. */
135 (void)sigemptyset(&set);
136 (void)sigaddset(&set, SIGIO);
137 if (sigprocmask(SIG_BLOCK, &set, &oset) != 0) {
138 swarn("%s: sigprocmask()", function);
139 return -1;
140 }
141
142 if (socksfd.state.inprogress) { /* non-blocking connect. */
143 /*
144 * this is bad. We don't know what address the socks server
145 * will use on our behalf yet. Lets wait for a SIGIO
146 * and then retry, unless client is blocking that signal,
147 * then we can only hope the client will retry on ENOBUFS,
148 * but we are probably screwed anyway.
149 */
150 if (sigismember(&oset, SIGIO)) {
151 swarnx("%s: SIGIO is being blocked by client", function);
152
153 if (sigprocmask(SIG_BLOCK, &oset, NULL) != 0) {
154 swarn("%s: sigprocmask()", function);
155 return -1;
156 }
157
158 errno = ENOBUFS;
159 return -1;
160 }
161
162
163 slog(LOG_DEBUG, "%s: waiting for signal from child", function);
164 sigsuspend(&oset); /* wait for sigchld. */
165
166 if (sigprocmask(SIG_BLOCK, &oset, NULL) != 0) {
167 swarn("%s: sigprocmask()", function);
168 return -1;
169 }
170
171 return Rgetsockname(s, name, namelen);
172 }
173
174 if (sigprocmask(SIG_SETMASK, &oset, NULL) != 0)
175 swarn("%s: sigprocmask()", function);
176 addr = socksfd.remote;
177 break;
178 }
179
180 case SOCKS_BIND:
181 addr = socksfd.remote;
182 break;
183
184 case SOCKS_UDPASSOCIATE:
185 swarnx("%s: getsockname() on udp sockets is not supported by the "
186 "socks protocol, trying to fake it.", function);
187
188 /*
189 * some clients might call this for no good reason, try to
190 * help them by returning a invalid address; if they are
191 * going to use it for anything, they will fail later though.
192 */
193
194 addr = socksfd.remote;
195 SET_SOCKADDR(&addr, AF_INET);
196 TOIN(&addr)->sin_addr.s_addr = htonl(INADDR_ANY);
197 TOIN(&addr)->sin_port = htons(0);
198 break;
199
200 default:
201 SERRX(socksfd.state.command);
202 }
203 }
204
205 *namelen = MIN(*namelen, salen(addr.ss_family));
206 sockaddrcpy(TOSS(name), &addr, (size_t)*namelen);
207
208 return 0;
209 }
210