⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sockd_request.c

📁 sock protocol ,it is useful!
💻 C
📖 第 1 页 / 共 3 页
字号:
		p = 1;		if (setsockopt(out, SOL_SOCKET, SO_REUSEADDR, &p, sizeof(p)) != 0)			swarn("%s: setsockopt(SO_REUSEADDR)", function);	}	if (PORTISRESERVED(bound.sin_port) && config.compat.sameport) {		uid_t euid;		socks_seteuid(&euid, config.uid.privileged);		p = bindresvport(out, &bound);		socks_reseteuid(config.uid.privileged, euid);	}	else		/* LINTED pointer casts may be troublesome */		p = sockd_bind(out, (struct sockaddr *)&bound, 1);	if (p != 0) { /* no such luck, bind any port and let client decide if ok. */		bound.sin_port	= htons(0);		/* LINTED pointer casts may be troublesome */		if ((p = sockd_bind(out, (struct sockaddr *)&bound, 0)) != 0)			swarn("%s: bind(%s)",			/* LINTED pointer casts may be troublesome */			function, sockaddr2string((struct sockaddr *)&bound, a, sizeof(a)));	}	if (p != 0) {		send_failure(request->s, &response, errno2reply(errno, response.version));		close(request->s);		close(out);		return;	}	/* rules permit? */	switch (request->req.command) {		case SOCKS_BIND: {			struct sockshost_t boundhost;			socklen_t boundlen;			boundlen = sizeof(bound);			/* LINTED pointer casts may be troublesome */			if (getsockname(out, (struct sockaddr *)&bound, &boundlen) != 0) {				swarn("%s: getsockname(out)", function);				close(request->s);				close(out);				return;			}			/* LINTED pointer casts may be troublesome */			sockaddr2sockshost((struct sockaddr *)&bound, &boundhost);			permit			= rulespermit(request->s, &io.rule, &io.state, &io.src, &boundhost);			iolog(&io.rule, &io.state, OPERATION_CONNECT, &io.src, &boundhost,			NULL, 0);			break;		}		case SOCKS_CONNECT:			permit			= rulespermit(request->s, &io.rule, &io.state, &io.src, &io.dst);			iolog(&io.rule, &io.state, OPERATION_CONNECT, &io.src, &io.dst,			NULL, 0);			break;		case SOCKS_UDPASSOCIATE: {			struct sockshost_t *src;			struct connectionstate_t replystate;			/*			 * Client is allowed to send a "incomplete" address.			 */			if (io.src.atype == SOCKS_ADDR_IPV4			&& (io.src.addr.ipv4.s_addr == htonl(0) || io.src.port == htons(0)))				src = NULL;			else				src = &io.src;			/* only set temporary here for one replypacket at a time. */			replystate				= io.state;			replystate.command	= SOCKS_UDPREPLY;			/* one direction is atleast in theory good enough. */			permit = rulespermit(request->s, &io.rule, &io.state, src, NULL)					|| rulespermit(request->s, &io.rule, &replystate, NULL, src);			iolog(&io.rule, &io.state, OPERATION_CONNECT, &io.src, &io.dst, NULL,			0);			break;		}		default:			SERRX(request->req.command);	}	if (!permit) {		send_failure(request->s, &response, SOCKS_NOTALLOWED);		close(request->s);		close(out);		return;	}	/*	 * Set up missing bits of io and send it to mother.	 */	switch (io.state.command) {		case SOCKS_BIND: {			struct sockd_io_t *iolist;			struct sockd_io_t bindio;			/* send this to proxyrelayer.			*/			struct sockaddr boundaddr;			/* address we listen on.				*/			struct sockaddr clientaddr;		/* clientaddress we forward to.		*/			socklen_t len;			int flags, emfile;			enum socketindex { client, childpipe, ourpipe, reply, remote };			/* array of sockets, indexed by above enums, -1 if not open. */			int sv[(int)(remote) + 1] = { -1, -1, -1, -1, -1 };			SASSERTX(sv[ELEMENTS(sv) - 1] == -1);			sv[client] = request->s;			if (listen(out, 5) != 0) {				swarn("%s: listen(out)", function);				send_failure(sv[client], &response, SOCKS_FAILURE);				closev(sv, ELEMENTS(sv));				break;			}			/* for accept(). */			if ((flags = fcntl(out, F_GETFL, 0)) == -1			|| fcntl(out, F_SETFL, flags | O_NONBLOCK) == -1) {				swarn("%s: fcntl()", function);				send_failure(sv[client], &response, SOCKS_FAILURE);				closev(sv, ELEMENTS(sv));				break;			}			len = sizeof(boundaddr);			if (getsockname(out, &boundaddr, &len) != 0) {				swarn("%s: getsockname()", function);				send_failure(sv[client], &response, SOCKS_FAILURE);				closev(sv, ELEMENTS(sv));				break;			}			sockaddr2sockshost(&boundaddr, &response.host);			response.reply	= (char)sockscode(response.version, SOCKS_SUCCESS);			/* LINTED pointer casts may be troublesome */			clientaddr = *(const struct sockaddr *)&request->from;			if (io.state.extension.bind) {				int pipev[2];				/*				 * The problem is that both we and the process which receives				 * the io packet needs to know when the client closes it's				 * connection, but _we_ need to receive a query from the				 * client on the connection aswell, and the io process would				 * get confused about that.  We try to hack around that				 * by making a "dummy" descriptor that the io process can				 * check as all other controlconnections and which we				 * can close when the client closes the real controlconnection,				 * so the io process can detect it.  Not very nice, no.				 */				if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipev) != 0) {					swarn("%s: socketpair()", function);					send_failure(sv[client], &response, SOCKS_FAILURE);					closev(sv, ELEMENTS(sv));					break;				}				sv[childpipe]	= pipev[0];				sv[ourpipe]		= pipev[1];				/* LINTED pointer casts may be troublesome */				((struct sockaddr_in *)&clientaddr)->sin_port = io.dst.port;			}			/* let client know what address we bound to on it's behalf. */			if (send_response(sv[client], &response) != 0) {				iolog(&io.rule, &io.state, OPERATION_ABORT, &io.src, &response.host,				NULL, 0);				closev(sv, ELEMENTS(sv));				break;			}			setproctitle("bindrelayer: %s -> %s",			sockaddr2string(&boundaddr, a, sizeof(a)),			sockaddr2string(&clientaddr, b, sizeof(b)));			/*			 * regardless of what kind of bind semantics are in use,			 * portnumber is something we ignore when checking remote peer.			 */			io.dst.port = htons(0);			emfile = 0;			iolist = NULL;			/* CONSTCOND */			while (1) {				struct ruleaddress_t ruleaddr;				struct sockaddr remoteaddr;		/* remote address we accepted.	*/				struct sockshost_t remotehost;	/* remote address, sockhost form.*/				struct sockaddr_in replyaddr;		/* address of bindreply socket.	*/				int fdbits = -1;				fd_set rset;				/* some sockets change, most remain the same. */				sv[reply]	= -1;				sv[remote]	= -1;				FD_ZERO(&rset);				FD_SET(sv[client], &rset);				fdbits = MAX(fdbits, sv[client]);				if (!emfile) {					FD_SET(out, &rset);					fdbits = MAX(fdbits, out);				}				++fdbits;				if ((p = selectn(fdbits, &rset, NULL, NULL, NULL)) <= 0)					SERR(p);				if (FD_ISSET(sv[client], &rset)) {					/*					 * nothing is normally expected on controlconnection so					 * assume it's a bind extension query or eof.					 */					struct request_t query;					struct response_t queryresponse;					struct negotiate_state_t state;					struct sockaddr queryaddr;					bzero(&state, sizeof(state));					bzero(&query, sizeof(query));					bzero(&queryresponse, sizeof(queryresponse));					query.auth = request->req.auth;					switch (p = recv_sockspacket(sv[client], &query, &state)) {						case -1:							iolog(&io.rule, &io.state, OPERATION_ABORT, &io.src,							&response.host, NULL, 0);							break;						case 0:							p = -1; /* session ended. */							break;						default: {							struct sockd_io_t *fio;							slog(LOG_DEBUG, "received request: %s",							socks_packet2string(&query, SOCKS_REQUEST));							switch (query.version) {								case SOCKS_V4:									queryresponse.version = SOCKS_V4REPLY_VERSION;									break;								case SOCKS_V5:									queryresponse.version = query.version;									break;								default:									SERRX(query.version);							}							sockshost2sockaddr(&query.host, &queryaddr);							if ((fio = io_find(iolist, &queryaddr)) == NULL) {								queryresponse.host.atype				= SOCKS_ADDR_IPV4;								queryresponse.host.addr.ipv4.s_addr = htonl(0);								queryresponse.host.port					= htons(0);							}							else {								SASSERTX(fio->state.command = SOCKS_BINDREPLY);								/* LINTED pointer casts may be troublesome */								SASSERTX(sockaddrareeq((struct sockaddr *)								&fio->in.laddr, &queryaddr));								/* LINTED pointer casts may be troublesome */								sockaddr2sockshost((struct sockaddr *)&fio->out.raddr,								&queryresponse.host);							}							if (fio != NULL) {								flushio(mother, sv[client], &queryresponse, fio);								emfile = MAX(0, emfile - 3); /* flushio() closes 3. */								iolist = io_remove(iolist, fio);								p = 0;							}							else								if ((p = send_response(sv[client], &queryresponse))								!= 0)									iolog(&io.rule, &io.state, OPERATION_ABORT, &io.src,									&response.host, NULL, 0);						}					}					if (p != 0)						break;				}				if (!FD_ISSET(out, &rset))					continue;				len = sizeof(remoteaddr);				if ((sv[remote] = acceptn(out, &remoteaddr, &len)) == -1) {					swarn("%s: accept(out)", function);					switch (errno) {#ifdef EPROTO						case EPROTO:			/* overloaded SVR4 error */#endif						case EWOULDBLOCK:		/* BSD */						case ECONNABORTED:	/* POSIX */						/* rest appears to be linux stuff according to apache src. */#ifdef ECONNRESET						case ECONNRESET:#endif#ifdef ETIMEDOUT						case ETIMEDOUT:#endif#ifdef EHOSTUNREACH						case EHOSTUNREACH:#endif#ifdef ENETUNREACH						case ENETUNREACH:#endif							continue;						case EMFILE:						case ENFILE:							++emfile;							continue;					}					break; /* errno is not ok. */				}				sockaddr2sockshost(&remoteaddr, &remotehost);				/* accepted connection; does remote address match requested? */				if (io.state.extension.bind				|| addressmatch(sockshost2ruleaddress(&io.dst, &ruleaddr),				&remotehost, SOCKS_TCP, 1)) {					bindio						= io; /* quick init of most stuff. */					bindio.src					= remotehost;					sockaddr2sockshost(&clientaddr, &bindio.dst);					bindio.state.command		= SOCKS_BINDREPLY;					permit = rulespermit(sv[client], &bindio.rule, &bindio.state,					&bindio.src, &bindio.dst);					iolog(&bindio.rule, &bindio.state, OPERATION_CONNECT,					&bindio.src, &bindio.dst, NULL, 0);				}				else {					slog(LOG_INFO, "%s(0): unexpected bindreply: %s -> %s",					VERDICT_BLOCKs, sockaddr2string(&remoteaddr, a, sizeof(a)),					sockshost2string(&io.src, b, sizeof(b)));					permit = 0;				}				if (!permit) {					close(sv[remote]);					continue; /* wait for next connect, but will there be one? */				}				/*				 * Someone connected to socket we listen to on behalf of client.				 * If we are using the bind extension, connect to address client				 * is listening on.  Otherwise, send the data on the connection				 * we already have.				 */				if (bindio.state.extension.bind) {					if ((sv[reply] = socket(AF_INET, SOCK_STREAM, 0)) == -1) {						swarn("%s: socket(SOCK_STREAM)", function);						switch (errno) {							case EMFILE:							case ENFILE:								++emfile;								/* FALLTHROUGH */							case ENOBUFS:								close(sv[remote]);								continue;						}						break; /* errno is not ok. */					}					setsockoptions(sv[reply]);					/* LINTED pointer casts may be troublesome */					replyaddr				= *(struct sockaddr_in *)&boundaddr;					replyaddr.sin_port	= htons(0);					/* LINTED pointer casts may be troublesome */					if (sockd_bind(sv[reply], (struct sockaddr *)&replyaddr, 0)					!= 0) {						/* LINTED pointer casts may be troublesome */						swarn("%s: bind(%s)", function,						sockaddr2string((struct sockaddr *)&replyaddr, a, sizeof(a)));						break;					}					len = sizeof(replyaddr);					/* LINTED pointer casts may be troublesome */					if (getsockname(sv[reply], (struct sockaddr *)&replyaddr, &len)					!= 0) {						swarn("%s: getsockname(sv[reply])", function);						if (errno == ENOBUFS) {							close(sv[remote]);							close(sv[reply]);							continue;						}						break;					}					slog(LOG_DEBUG, "connecting to %s",					sockaddr2string(&clientaddr, a, sizeof(a)));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -