📄 sockd_io.c
字号:
SASSERTX(io->allocated); if (io->rule.log.disconnect) { char logmsg[MAXHOSTNAMELEN * 2 + 1024]; char in[MAXSOCKADDRSTRING], out[MAXSOCKADDRSTRING]; /* LINTED pointer casts may be troublesome */ sockaddr2string((struct sockaddr *)&io->in.raddr, in, sizeof(in)); switch (io->state.command) { case SOCKS_BIND: case SOCKS_BINDREPLY: case SOCKS_CONNECT: /* LINTED pointer casts may be troublesome */ sockaddr2string((struct sockaddr *)&io->out.raddr, out, sizeof(out)); break; case SOCKS_UDPASSOCIATE: snprintf(out, sizeof(out), "`world'"); break; default: SERRX(io->state.command); } snprintf(logmsg, sizeof(logmsg), "%s: %lu -> %s -> %lu, %lu -> %s -> %lu", protocol2string(io->state.protocol), (unsigned long)io->in.written, in, (unsigned long)io->in.read, (unsigned long)io->out.written, out, (unsigned long)io->out.read); errno = errno_s; if (fd < 0) switch (status) { case IO_SRCBLOCK: slog(LOG_INFO, "%s: delayed sourceblock", logmsg); break; case IO_ERROR: swarn("%s: connection error", logmsg); break; case IO_CLOSE: slog(LOG_INFO, "%s: connection closed", logmsg); break; case IO_TIMEOUT: slog(LOG_INFO, "%s: connection i/o expired", logmsg); break; default: slog(LOG_INFO, "%s: short read/write", logmsg); } else if (fd == io->in.s || fd == io->control.s) { switch (status) { case IO_SRCBLOCK: slog(LOG_INFO, "%s: delayed sourceblock", logmsg); break; case IO_ERROR: swarn("%s: client error", logmsg); break; case IO_CLOSE: slog(LOG_INFO, "%s: client closed", logmsg); break; case IO_TIMEOUT: slog(LOG_INFO, "%s: client i/o expired", logmsg); break; default: slog(LOG_INFO, "%s: client short read/write", logmsg); } } else if (fd == io->out.s) { switch (status) { case IO_SRCBLOCK: slog(LOG_INFO, "%s: delayed sourceblock", logmsg); break; case IO_ERROR: swarn("%s: remote error", logmsg); break; case IO_CLOSE: slog(LOG_INFO, "%s: remote closed", logmsg); break; case IO_TIMEOUT: slog(LOG_INFO, "%s: remote i/o expired", logmsg); break; default: slog(LOG_INFO, "%s: remote short read/write", logmsg); } } else SERRX(fd); } /* this may end up logging same disconnect twice, but not our choice. */ if (io->acceptrule.log.disconnect) { struct connectionstate_t state = io->state; state.command = SOCKS_DISCONNECT; iolog(&io->acceptrule, &state, OPERATION_DISCONNECT, &io->src, &io->dst, NULL, 0); } close_iodescriptors(io); io->allocated = 0; if (mother != -1) { const char b = SOCKD_FREESLOT; /* ack io slot free. */ if (writen(mother, &b, sizeof(b)) != sizeof(b)) swarn("%s: writen(): mother", function); } proctitleupdate();}voidclose_iodescriptors(io) const struct sockd_io_t *io;{ close(io->in.s); close(io->out.s); switch (io->state.command) { case SOCKS_CONNECT: break; case SOCKS_BIND: case SOCKS_BINDREPLY: if (!io->state.extension.bind) break; /* else: */ /* FALLTHROUGH */ case SOCKS_UDPASSOCIATE: close(io->control.s); break; default: SERRX(io->state.command); }}intrecv_io(s, io) int s; struct sockd_io_t *io;{ const char *function = "recv_io()"; int i, fdexpect, fdreceived; size_t length = 0; struct iovec iovec[1]; struct msghdr msg; CMSG_AALLOC(sizeof(int) * FDPASS_MAX); if (io == NULL) { /* child semantics; find a io ourselves. */ for (i = 0; i < ioc; ++i) if (!iov[i].allocated) { io = &iov[i]; break; } if (io == NULL) { /* * either mother died/closed connection, or there is another error. * Both cases should be rare so try to find out what the problem is. */ char buf; if (recv(s, &buf, sizeof(buf), MSG_PEEK) > 0) SERRX(allocated()); return -1; } } iovec[0].iov_base = io; iovec[0].iov_len = sizeof(*io); length += iovec[0].iov_len; msg.msg_iov = iovec; msg.msg_iovlen = ELEMENTS(iovec); msg.msg_name = NULL; msg.msg_namelen = 0; CMSG_SETHDR_RECV(sizeof(cmsgmem)); if (recvmsgn(s, &msg, 0, length) != (ssize_t)length) { swarn("%s: recvmsgn()", function); return -1; } /* figure out how many descriptors we are supposed to be passed. */ switch (io->state.command) { case SOCKS_BIND: case SOCKS_BINDREPLY: if (io->state.extension.bind) fdexpect = 3; /* in, out, control. */ else fdexpect = 2; /* in and out. */ break; case SOCKS_CONNECT: fdexpect = 2; /* in and out */ break; case SOCKS_UDPASSOCIATE: fdexpect = 3; /* in, out, and control */ break; default: SERRX(io->state.command); } /* calculate expected datalen */#if !HAVE_DEFECT_RECVMSG SASSERT(CMSG_GETLEN(msg) == sizeof(int) * fdexpect);#endif /* * Get descriptors sent us. */ fdreceived = 0; CMSG_GETOBJECT(io->in.s, sizeof(io->in.s) * fdreceived++); CMSG_GETOBJECT(io->out.s, sizeof(io->out.s) * fdreceived++); switch (io->state.command) { case SOCKS_BIND: case SOCKS_BINDREPLY: if (io->state.extension.bind) CMSG_GETOBJECT(io->control.s, sizeof(io->control.s) * fdreceived++); else io->control.s = -1; break; case SOCKS_CONNECT: io->control.s = -1; break; case SOCKS_UDPASSOCIATE: CMSG_GETOBJECT(io->control.s, sizeof(io->control.s) * fdreceived++); break; default: SERRX(io->state.command); } time(&io->time); io->allocated = 1;#if DEBUG printfd(io, "received");#endif return 0;}static voidio_clearset(io, set) const struct sockd_io_t *io; fd_set *set;{ FD_CLR(io->in.s, set); FD_CLR(io->out.s, set); switch (io->state.command) { case SOCKS_CONNECT: break; case SOCKS_BIND: case SOCKS_BINDREPLY: if (!io->state.extension.bind) break; /* else: */ /* FALLTHROUGH */ case SOCKS_UDPASSOCIATE: FD_CLR(io->control.s, set); break; default: SERRX(io->state.command); }}static intallocated(void){ int i, alloc; for (i = 0, alloc = 0; i < ioc; ++i) if (iov[i].allocated) ++alloc; return alloc;}static voiddoio(mother, io, rset, wset, flags) int mother; struct sockd_io_t *io; fd_set *rset, *wset; int flags;{ const char *function = "doio()"; /* CONSTCOND */ char buf[MAX(SOCKD_BUFSIZETCP, SOCKD_BUFSIZEUDP) + sizeof(struct udpheader_t)]; ssize_t r, w; SASSERTX(io->allocated); SASSERTX((FD_ISSET(io->in.s, rset) && FD_ISSET(io->out.s, wset)) || (FD_ISSET(io->in.s, wset) && FD_ISSET(io->out.s, rset)) || (flags & MSG_OOB) || (io->control.s != -1 && FD_ISSET(io->control.s, rset))); switch (io->state.protocol) { case SOCKS_TCP: { int bad; /* from in to out... */ if (FD_ISSET(io->in.s, rset) && FD_ISSET(io->out.s, wset)) { bad = -1; r = io_rw(&io->in, &io->out, &bad, buf, flags); if (bad != -1) { delete_io(mother, io, bad, r); return; } iolog(&io->rule, &io->state, OPERATION_IO, &io->src, &io->dst, buf, (size_t)r); } /* ... and out to in. */ if (FD_ISSET(io->out.s, rset) && FD_ISSET(io->in.s, wset)) { bad = -1; r = io_rw(&io->out, &io->in, &bad, buf, flags); if (bad != -1) { delete_io(mother, io, bad, r); return; } iolog(&io->rule, &io->state, OPERATION_IO, &io->dst, &io->src, buf, (size_t)r); } break; } case SOCKS_UDP: { struct udpheader_t header; socklen_t fromlen; int permit; /* * UDP is sadly considerably more complex than TCP; * need to check rules on each packet, need to check if it * was received from expected src, etc. */ /* udp to relay from client to destination? */ if (FD_ISSET(io->in.s, rset) && FD_ISSET(io->out.s, wset)) { const int lflags = flags & ~MSG_OOB; struct sockaddr from; fromlen = sizeof(from); if ((r = recvfrom(io->in.s, buf, io->out.sndlowat, lflags, &from, &fromlen)) == -1) { delete_io(mother, io, io->in.s, r); return; } UDPFROMLENCHECK(io->in.s, fromlen); /* * If client hasn't sent us it's address yet we have to * assume the first packet is from is it. * Client can only blame itself if not. */ if (io->in.raddr.sin_addr.s_addr == htonl(INADDR_ANY) || io->in.raddr.sin_port == htons(0)) { if (io->in.raddr.sin_addr.s_addr == htonl(INADDR_ANY)) /* LINTED pointer casts may be troublesome */ io->in.raddr.sin_addr.s_addr = ((struct sockaddr_in *)&from)->sin_addr.s_addr; if (io->in.raddr.sin_port == htons(0)) /* LINTED pointer casts may be troublesome */ io->in.raddr.sin_port = ((struct sockaddr_in *)&from)->sin_port; /* LINTED pointer casts may be troublesome */ sockaddr2sockshost((struct sockaddr *)&io->in.raddr, &io->src); } /* * When we receive the first packet we also have a fixed source * so connect the socket, both for better performance and so * that getpeername() will work on it (libwrap/rulespermit()). */ if (io->in.read == 0) { /* could happen more than once, but ok. */ struct connectionstate_t rstate; /* LINTED pointer casts may be troublesome */ if (!sockaddrareeq((struct sockaddr *)&io->in.raddr, &from)) { char src[MAXSOCKADDRSTRING], dst[MAXSOCKADDRSTRING]; /* perhaps this should be LOG_DEBUG. */ slog(LOG_NOTICE, "%s(0): %s: expected from %s, got it from %s", VERDICT_BLOCKs, protocol2string(io->state.protocol), /* LINTED pointer casts may be troublesome */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -