2
* Copyright (c) 1997, 1998, 1999, 2000, 2001
3
* Inferno Nettverk A/S, Norway. All rights reserved.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
8
* 1. The above copyright notice, this list of conditions and the following
9
* disclaimer must appear in all copies of the software, derivative works
10
* or modified versions, and any portions thereof, aswell as in all
11
* supporting documentation.
12
* 2. All advertising materials mentioning features or use of this software
13
* must display the following acknowledgement:
14
* This product includes software developed by
15
* Inferno Nettverk A/S, Norway.
16
* 3. The name of the author may not be used to endorse or promote products
17
* derived from this software without specific prior written permission.
19
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
* Inferno Nettverk A/S requests users of this software to return to
32
* Software Distribution Coordinator or sdc@inet.no
33
* Inferno Nettverk A/S
39
* any improvements or extensions that they make and grant Inferno Nettverk A/S
40
* the rights to redistribute these changes.
46
static const char rcsid[] =
47
"$Id: config.c,v 1.150 2001/12/12 14:42:10 karls Exp $";
52
const char *function = "genericinit()";
55
if (!sockscf.state.init) {
56
#if !HAVE_SETPROCTITLE
57
/* create a backup to avoid setproctitle replacement overwriting it. */
58
if ((__progname = strdup(__progname)) == NULL)
59
serrx(EXIT_FAILURE, "%s: %s", function, NOMEM);
60
#endif /* !HAVE_SETPROCTITLE */
63
if (readconfig(sockscf.option.configfile) != 0)
72
switch (sockscf.resolveprotocol) {
73
case RESOLVEPROTOCOL_TCP:
74
#if !HAVE_NO_RESOLVESTUFF
75
_res.options |= RES_USEVC;
76
#else /* HAVE_NO_RESOLVESTUFF */
77
SERRX(sockscf.resolveprotocol);
78
#endif /* HAVE_NO_RESOLVESTUFF */
81
case RESOLVEPROTOCOL_UDP:
82
case RESOLVEPROTOCOL_FAKE:
86
SERRX(sockscf.resolveprotocol);
89
if (!sockscf.state.init)
90
if (sockscf.option.lbuf)
91
for (i = 0; i < sockscf.log.fpc; ++i)
92
if (setvbuf(sockscf.log.fpv[i], NULL, _IOLBF, 0) != 0)
93
swarn("%s: setvbuf(_IOLBF)", function);
95
sockscf.state.init = 1;
97
#if !HAVE_NO_RESOLVESTUFF
99
#endif /* !HAVE_NO_RESOLVSTUFF */
106
const struct route_t *newroute;
108
const char *function = "addroute()";
109
static const struct serverstate_t state;
110
struct route_t *route;
112
if ((route = (struct route_t *)malloc(sizeof(*route))) == NULL)
113
serrx(EXIT_FAILURE, "%s: %s", function, NOMEM);
118
/* if no command set, set all. */
119
if (memcmp(&state.command, &route->gw.state.command, sizeof(state.command))
121
memset(&route->gw.state.command, UCHAR_MAX,
122
sizeof(route->gw.state.command));
124
/* if no protocol set, set all. */
125
if (memcmp(&state.protocol, &route->gw.state.protocol,
126
sizeof(state.protocol)) == 0)
127
memset(&route->gw.state.protocol, UCHAR_MAX,
128
sizeof(route->gw.state.protocol));
130
/* if no proxyprotocol set, set all except msproxy. */
131
if (memcmp(&state.proxyprotocol, &route->gw.state.proxyprotocol,
132
sizeof(state.proxyprotocol)) == 0) {
133
memset(&route->gw.state.proxyprotocol, UCHAR_MAX,
134
sizeof(route->gw.state.proxyprotocol));
135
route->gw.state.proxyprotocol.msproxy_v2 = 0;
138
/* switch off commands/protocols set but not supported by proxyprotocol. */
139
if (!route->gw.state.proxyprotocol.socks_v5) {
140
route->gw.state.command.udpassociate = 0;
141
route->gw.state.protocol.udp = 0;
144
if (!route->gw.state.proxyprotocol.socks_v4
145
&& !route->gw.state.proxyprotocol.msproxy_v2)
146
route->gw.state.command.bind = 0;
148
/* if no method set, set all we support. */
149
if (route->gw.state.methodc == 0) {
150
int *methodv = route->gw.state.methodv;
151
size_t *methodc = &route->gw.state.methodc;
153
methodv[(*methodc)++] = AUTHMETHOD_NONE;
154
methodv[(*methodc)++] = AUTHMETHOD_UNAME;
157
if (route->src.atype == SOCKS_ADDR_IFNAME)
158
yyerror("interfacenames not supported for src address");
160
if (route->dst.atype == SOCKS_ADDR_IFNAME)
161
yyerror("interfacenames not supported for src address");
163
if (sockscf.route == NULL) {
164
sockscf.route = route;
165
sockscf.route->number = 1;
168
/* append rule to the end of list. */
169
struct route_t *lastroute;
171
lastroute = sockscf.route;
172
while (lastroute->next != NULL)
173
lastroute = lastroute->next;
175
route->number = lastroute->number + 1;
176
lastroute->next = route;
186
const struct route_t *route;
188
char hstring[MAXSOCKSHOSTSTRING];
189
char addr[MAXRULEADDRSTRING];
191
slog(LOG_INFO, "route #%d", route->number);
193
slog(LOG_INFO, "src: %s",
194
ruleaddress2string(&route->src, addr, sizeof(addr)));
196
slog(LOG_INFO, "dst: %s",
197
ruleaddress2string(&route->dst, addr, sizeof(addr)));
199
slog(LOG_INFO, "gateway: %s",
200
sockshost2string(&route->gw.host, hstring, sizeof(hstring)));
202
showstate(&route->gw.state);
207
socks_getroute(req, src, dst)
208
const struct request_t *req;
209
const struct sockshost_t *src;
210
const struct sockshost_t *dst;
212
/* const char *function = "socks_getroute()"; */
213
struct route_t *route;
220
for (route = sockscf.route; route != NULL; route = route->next) {
221
if (route->state.bad)
223
if (BADROUTE_EXPIRE == 0
224
|| difftime(time(NULL), route->state.badtime) <= BADROUTE_EXPIRE)
227
route->state.bad = 0;
229
switch (req->version) {
231
if (!route->gw.state.proxyprotocol.socks_v4)
234
switch (req->host.atype) {
235
case SOCKS_ADDR_IPV4:
238
case SOCKS_ADDR_IPV6:
239
case SOCKS_ADDR_DOMAIN:
240
continue; /* not failure, just checking. */
243
SERRX(req->host.atype); /* failure, nothing else exists. */
248
if (!route->gw.state.proxyprotocol.socks_v5)
251
switch (req->host.atype) {
252
case SOCKS_ADDR_IPV4:
253
case SOCKS_ADDR_IPV6:
254
case SOCKS_ADDR_DOMAIN:
258
SERRX(req->host.atype); /* failure, nothing else exists. */
263
if (!route->gw.state.proxyprotocol.msproxy_v2)
268
if (!route->gw.state.proxyprotocol.http_v1_0)
276
switch (req->command) {
278
if (!route->gw.state.command.bind)
281
if (req->host.atype == SOCKS_ADDR_IPV4
282
&& req->host.addr.ipv4.s_addr == htonl(0))
283
if (req->version == MSPROXY_V2)
284
; /* supports binding wildcard */
285
else if (!route->gw.state.extension.bind)
290
if (!route->gw.state.command.connect)
294
case SOCKS_UDPASSOCIATE:
295
if (!route->gw.state.command.udpassociate)
303
/* server supports protocol? */
304
switch (req->command) {
307
if (!route->gw.state.protocol.tcp)
309
protocol = SOCKS_TCP;
312
case SOCKS_UDPASSOCIATE:
313
if (!route->gw.state.protocol.udp)
315
protocol = SOCKS_UDP;
323
if (!addressmatch(&route->src, src, protocol, 0))
327
if (!addressmatch(&route->dst, dst, protocol, 0))
330
if (route->state.direct)
331
return NULL; /* don't use any route, connect directly. */
333
break; /* all matched */
341
socks_connectroute(s, packet, src, dst)
343
struct socks_t *packet;
344
const struct sockshost_t *src;
345
const struct sockshost_t *dst;
347
const char *function = "socks_connectroute()";
348
int sdup, current_s, errno_s;
349
struct route_t *route;
352
* This is a little tricky since we attempt to support trying
353
* more than one socksserver. If the first one fails, we try
354
* the next, etc. Ofcourse, if connect() on one socket fails,
355
* that socket can no longer be used, so we need to be able to
356
* copy/dup the original socket as much as possible. Later,
357
* if it turned out a connection failed and we had to use a
358
* different socket than the orignal 's', we try to dup the
359
* differently numbered socket to 's' and hope the best.
361
* sdup: copy of the original socket. Need to create this
362
* before the first connectattempt since the connectattempt
363
* could prevent us from doing it later, depending on failure
366
* current_s: socket to use for next connection attempt. For the
367
* first attempt this is 's'.
370
errno = 0; /* let caller differentiate between missing route and not.*/
374
while ((route = socks_getroute(&packet->req, src, dst)) != NULL) {
375
char hstring[MAXSOCKSHOSTSTRING];
377
/* inside loop since if no route, no need for it. */
379
sdup = socketoptdup(s);
382
if ((current_s = socketoptdup(sdup == -1 ? s : sdup)) == -1)
385
slog(LOG_DEBUG, "%s: trying route #%d (%s)",
386
function, route->number,
387
sockshost2string(&route->gw.host, hstring, sizeof(hstring)));
389
if (socks_connect(current_s, &route->gw.host) == 0)
393
* Check whether the error indicates bad socksserver or
396
if (errno == EINPROGRESS) {
397
SASSERTX(current_s == s);
400
else if (errno == EADDRINUSE) {
401
/* see Rbind() for explanation. */
402
SASSERTX(current_s == s);
407
swarn("%s: socks_connect(%s)",
408
function, sockshost2string(&route->gw.host, hstring,
410
socks_badroute(route);
421
if (current_s != s && current_s != -1) {
422
/* created a new socket for connect, need to make it same descriptor #. */
423
if (dup2(current_s, s) == -1) {
429
#if SOCKS_SERVER && HAVE_LIBWRAP
430
if ((current_s = fcntl(s, F_GETFD, 0)) == -1
431
|| fcntl(s, F_SETFD, current_s | FD_CLOEXEC) == -1)
432
swarn("%s: fcntl(F_GETFD/F_SETFD)", function);
439
packet->gw = route->gw;
441
/* need to set up misc. crap for msproxy stuff. */
442
if (!init && route->gw.state.proxyprotocol.msproxy_v2) {
443
if (msproxy_init() != 0)
444
; /* yes, then what? */
454
socks_badroute(route)
455
struct route_t *route;
457
const char *function = "socks_badroute()";
459
slog(LOG_DEBUG, "%s: badrouting route #%d", function, route->number);
460
route->state.bad = 1;
461
time(&route->state.badtime);
466
socks_requestpolish(req, src, dst)
467
struct request_t *req;
468
const struct sockshost_t *src;
469
const struct sockshost_t *dst;
471
const char *function = "socks_requestpolish()";
472
const unsigned char originalversion = req->version;
474
if (socks_getroute(req, src, dst) != NULL)
477
switch (req->command) {
480
* bind semantics differ between v4 and everything else.
481
* Assuming we always start with v5 semantics makes the
482
* following code much simpler.
484
SASSERTX(req->version == SOCKS_V5);
490
case SOCKS_UDPASSOCIATE:
491
SERRX(req->command); /* currently not implemented, shouldn't happen. */
499
* Try all proxyprotocols we support.
502
req->version = SOCKS_V4;
503
if (socks_getroute(req, src, dst) != NULL) {
504
if (req->command == SOCKS_BIND) /* v4/v5 difference in portsemantics. */
505
/* LINTED pointer casts may be troublesome */
506
req->host.port = TOIN(&sockscf.state.lastconnect)->sin_port;
510
req->version = HTTP_V1_0;
511
if (socks_getroute(req, src, dst) != NULL)
514
req->version = MSPROXY_V2;
515
if (socks_getroute(req, src, dst) != NULL)
518
req->version = originalversion;
520
/* changing proxyprotocol didn't do it, can we try other things? */
521
switch (req->command) {
523
if (req->host.addr.ipv4.s_addr == htonl(0)) {
524
in_port_t originalport;
526
/* attempting to use bind extension, can we retry without it? */
527
/* LINTED pointer casts may be troublesome */
528
if (!ADDRISBOUND(sockscf.state.lastconnect)) {
529
slog(LOG_DEBUG, "%s: couldn't find route for bind(2), "
530
"try enabling \"extension: bind\"?", function);
534
originalport = req->host.port;
535
fakesockaddr2sockshost(&sockscf.state.lastconnect, &req->host);
536
/* keep portnumber req. for bind(2), not a previous connect(2). */
537
req->host.port = originalport;
539
if (socks_requestpolish(req, src, dst) == NULL)
540
return NULL; /* giving up. */
543
* else, it may be that socks_requestpolish() was
544
* forced to change req.version to succeed. We may
545
* the need to change req->host.port due to difference
546
* in v4 and v5 semantics.
548
if (req->version != originalversion) { /* version changed. */
549
SASSERTX(originalversion == SOCKS_V5);
551
switch (req->version) {
552
case SOCKS_V4: /* the only one with this strangeness. */
553
/* LINTED pointer casts may be troublesome */
555
= TOIN(&sockscf.state.lastconnect)->sin_port;
568
#endif /* SOCKS_CLIENT */
572
const struct serverstate_t *state;
577
bufused = snprintfn(buf, sizeof(buf), "command(s): ");
578
if (state->command.bind)
579
bufused += snprintfn(&buf[bufused], sizeof(buf) - bufused, "%s, ",
581
if (state->command.bindreply)
582
bufused += snprintfn(&buf[bufused], sizeof(buf) - bufused, "%s, ",
584
if (state->command.connect)
585
bufused += snprintfn(&buf[bufused], sizeof(buf) - bufused, "%s, ",
587
if (state->command.udpassociate)
588
bufused += snprintfn(&buf[bufused], sizeof(buf) - bufused, "%s, ",
589
SOCKS_UDPASSOCIATEs);
590
if (state->command.udpreply)
591
bufused += snprintfn(&buf[bufused], sizeof(buf) - bufused, "%s, ",
595
bufused = snprintfn(buf, sizeof(buf), "extension(s): ");
596
if (state->extension.bind)
597
bufused += snprintfn(&buf[bufused], sizeof(buf) - bufused, "bind");
600
bufused = snprintfn(buf, sizeof(buf), "protocol(s): ");
601
protocols2string(&state->protocol,
602
&buf[bufused], sizeof(buf) - bufused);
605
showmethod(state->methodc, state->methodv);
607
bufused = snprintfn(buf, sizeof(buf), "proxyprotocol(s): ");
608
proxyprotocols2string(&state->proxyprotocol,
609
&buf[bufused], sizeof(buf) - bufused);
615
showmethod(methodc, methodv)
621
slog(LOG_INFO, "method(s): %s",
622
methods2string(methodc, methodv, buf, sizeof(buf)));