📄 sockd_request.c
字号:
/* * Copyright (c) 1997, 1998, 1999 * Inferno Nettverk A/S, Norway. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. The above copyright notice, this list of conditions and the following * disclaimer must appear in all copies of the software, derivative works * or modified versions, and any portions thereof, aswell as in all * supporting documentation. * 2. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by * Inferno Nettverk A/S, Norway. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Inferno Nettverk A/S requests users of this software to return to * * Software Distribution Coordinator or sdc@inet.no * Inferno Nettverk A/S * Oslo Research Park * Gaustadal閑n 21 * N-0349 Oslo * Norway * * any improvements or extensions that they make and grant Inferno Nettverk A/S * the rights to redistribute these changes. * */#include "common.h"static const char rcsid[] ="$Id: sockd_request.c,v 1.110 1999/12/22 09:29:27 karls Exp $";/* * Since it only handles one client at a time there is no possibility * for the mother to send a new client before we have got rid of the * old one and thus no need for locking even on broken systems. * (#ifdef HAVE_SENDMSG_DEADLOCK) * XXX I have started to work on fixing this, so this process too * can support multiple clients, perhaps for a later release I will * have time to complete it. Will also fix the terrible fact * that we just sit around and wait if the command is bind, wasting * the whole process on practically nothing. */__BEGIN_DECLSstatic voiddorequest __P((int mother, const struct sockd_request_t *request));/* * When a complete request has been read, this function can be * called. It will perform the request "request->req" and send the * result to "mother". */static voidflushio __P((int mother, int clientcontrol, const struct response_t *response, struct sockd_io_t *io));/* * "flushes" a complete io object and free's any state/resources held by it. * "mother" is connection to mother for sending the io. * "clientcontrol" is the client connection. * "response" is the response to be sent the client. * "io" is the io object sent mother. */static voidproctitleupdate __P((const struct sockaddr *from));/* * Updates the title of this process. */static struct sockd_io_t *io_add __P((struct sockd_io_t *iolist, const struct sockd_io_t *newio));/* * Adds _a copy_ of the object "newio" to the list "iolist". * Returns a pointer to the (new) iolist. */static struct sockd_io_t *io_remove __P((struct sockd_io_t *iolist, struct sockd_io_t *rmio));/* * Removes the object "rmio" from the list "iolist". * Returns a pointer to the (new) iolist. */static struct sockd_io_t *io_find __P((struct sockd_io_t *iolist, const struct sockaddr *addr));/* * Scans "iolist" for a object that contains "addr" as a local address. * If "addr" is NULL, returns "iolist". * Returns: * On success: pointer to the matching io object. * On failure: NULL. */__END_DECLSvoidrun_request(mother) struct sockd_mother_t *mother;{ const char *function = "run_request()"; struct sockd_request_t req;#if DIAGNOSTIC const int freec = freedescriptors(config.option.debug ? "start" : NULL);#endif /* DIAGNOSTIC */ proctitleupdate(NULL); /* CONSTCOND */ while (1) { /* * Get request from mother, perform it, get next request. */ const char command = SOCKD_FREESLOT; proctitleupdate(NULL); if (recv_req(mother->s, &req) == -1) sockdexit(-EXIT_FAILURE); /* LINTED pointer casts may be troublesome */ proctitleupdate((struct sockaddr *)&req.from); dorequest(mother->s, &req); if (writen(mother->ack, &command, sizeof(command)) != sizeof(command)) serr(EXIT_FAILURE, "%s: sending ack to mother failed", function);#if DIAGNOSTIC SASSERTX(freec == freedescriptors(config.option.debug ? "end" : NULL));#endif /* DIAGNOSTIC */ }}intrecv_req(s, req) int s; struct sockd_request_t *req;{ const char *function = "recv_req()"; int fdexpect, fdreceived, r; struct iovec iovec[1]; struct msghdr msg; CMSG_AALLOC(sizeof(int)); iovec[0].iov_base = req; iovec[0].iov_len = sizeof(*req); msg.msg_iov = iovec; msg.msg_iovlen = ELEMENTS(iovec); msg.msg_name = NULL; msg.msg_namelen = 0; CMSG_SETHDR_RECV(sizeof(cmsgmem)); if ((r = recvmsgn(s, &msg, 0, sizeof(*req))) != sizeof(*req)) { switch (r) { case -1: swarn("%s: recvmsg() from mother", function); break; case 0: slog(LOG_DEBUG, "%s: recvmsg(): mother closed connection", function); break; default: swarnx("%s: recvmsg(): unexpected %d/%d bytes from mother", function, r, sizeof(*req)); } return -1; } fdexpect = 1;#if !HAVE_DEFECT_RECVMSG SASSERT(CMSG_GETLEN(msg) == sizeof(int) * fdexpect);#endif fdreceived = 0; CMSG_GETOBJECT(req->s, sizeof(req->s) * fdreceived++); /* pointer fixup */ req->req.auth = &req->state.auth; return 0;}static voiddorequest(mother, request) int mother; const struct sockd_request_t *request;{ const char *function = "dorequest()"; static const struct sockd_io_t ioinit; struct sockaddr_in bound; struct sockd_io_t io; struct response_t response; char a[MAXSOCKSHOSTSTRING], b[MAXSOCKSHOSTSTRING]; int p, permit, out; slog(LOG_DEBUG, "received request: %s", socks_packet2string(&request->req, SOCKS_REQUEST)); bzero(&response, sizeof(response)); response.host = request->req.host; response.auth = request->req.auth; io = ioinit; io.acceptrule = request->rule; io.state = request->state; io.state.extension = config.extension; /* * examine client request. */ /* supported version? */ switch (request->req.version) { case SOCKS_V4: response.version = SOCKS_V4REPLY_VERSION; /* recognized command for this version? */ switch (request->req.command) { case SOCKS_BIND: case SOCKS_CONNECT: io.state.protocol = SOCKS_TCP; break; default: /* LINTED pointer casts may be troublesome */ slog(LOG_INFO, "%s: unrecognized v%d command: %d", sockaddr2string((const struct sockaddr *)&request->from, a, sizeof(a)), request->req.version, request->req.command); send_failure(request->s, &response, SOCKS_FAILURE); close(request->s); return; } /* supported address format for this version? */ switch (request->req.host.atype) { case SOCKS_ADDR_IPV4: break; default: /* LINTED pointer casts may be troublesome */ slog(LOG_INFO, "%s: unrecognized v%d address type: %d", sockaddr2string((const struct sockaddr *)&request->from, a, sizeof(a)), request->req.version, request->req.host.atype); send_failure(request->s, &response, SOCKS_ADDR_UNSUPP); close(request->s); return; } break; /* SOCKS_V4 */ case SOCKS_V5: response.version = request->req.version; /* recognized command for this version? */ switch (request->req.command) { case SOCKS_BIND: case SOCKS_CONNECT: io.state.protocol = SOCKS_TCP; break; case SOCKS_UDPASSOCIATE: io.state.protocol = SOCKS_UDP; break; default: /* LINTED pointer casts may be troublesome */ slog(LOG_INFO, "%s: unrecognized v%d command: %d", sockaddr2string((const struct sockaddr *)&request->from, a, sizeof(a)), request->req.version, request->req.command); send_failure(request->s, &response, SOCKS_CMD_UNSUPP); close(request->s); return; } /* supported address format for this version? */ switch (request->req.host.atype) { case SOCKS_ADDR_IPV4: case SOCKS_ADDR_DOMAIN: break; default: /* LINTED pointer casts may be troublesome */ slog(LOG_INFO, "%s: unrecognized v%d address type: %d", sockaddr2string((const struct sockaddr *)&request->from, a, sizeof(a)), request->req.version, request->req.host.atype); send_failure(request->s, &response, SOCKS_ADDR_UNSUPP); close(request->s); return; } break; /* SOCKS_V5 */ default: SERRX(request->req.version); } /* * packet looks ok, fill in remaining bits needed to check rules. */ switch (request->req.command) { case SOCKS_BIND: /* LINTED pointer casts may be troublesome */ sockaddr2sockshost((const struct sockaddr *)&request->from, &io.src); io.dst = request->req.host; if (io.dst.atype != SOCKS_ADDR_IPV4 || io.dst.addr.ipv4.s_addr != htonl(0) || io.dst.port == htons(0)) io.state.extension.bind = 0; /* not requesting bind extension. */ break; case SOCKS_CONNECT: /* LINTED pointer casts may be troublesome */ sockaddr2sockshost((const struct sockaddr *)&request->from, &io.src); io.dst = request->req.host; break; case SOCKS_UDPASSOCIATE: /* * for UDP_ASSOCIATE we are getting clients udp address, * not destination in request. * Destination address will be checked in the i/o loop for * each destination, for now just set it to INADDR_ANY. */ io.src = request->req.host; io.dst.atype = SOCKS_ADDR_IPV4; io.dst.addr.ipv4.s_addr = htonl(INADDR_ANY); io.dst.port = htons(0); break; default: SERRX(request->req.command); } /* socket to use for outgoing connection. */ switch (io.state.protocol) { case SOCKS_TCP: if ((out = socket(AF_INET, SOCK_STREAM, 0)) == -1) swarn("%s: socket(SOCK_STREAM)", function); break; case SOCKS_UDP: if ((out = socket(AF_INET, SOCK_DGRAM, 0)) == -1) swarn("%s: socket(SOCK_DGRAM)", function); break; default: SERRX(io.state.protocol); } if (out == -1) { send_failure(request->s, &response, SOCKS_FAILURE); close(request->s); return; } setsockoptions(out); /* find out what address to bind on clients behalf. */ bound = *config.externalv; switch (request->req.command) { case SOCKS_BIND: /* find out what port to bind; v4/v5 semantics? bind extension? */ switch (request->req.version) { case SOCKS_V4: if (io.state.extension.bind) bound.sin_port = io.dst.port; else /* best we can try for is to use same port as source. */ bound.sin_port = request->from.sin_port; break; case SOCKS_V5: bound.sin_port = io.dst.port; break; default: SERRX(request->req.version); } break; case SOCKS_CONNECT: bound.sin_port = request->from.sin_port; break; case SOCKS_UDPASSOCIATE: bound.sin_port = request->req.host.port; break; default: SERRX(request->req.command); } /* * bind socket. */ if (config.compat.reuseaddr) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -