📄 sockd_io.c
字号:
sockaddr2string((struct sockaddr *)&io->in.raddr, src, sizeof(src)), sockaddr2string(&from, dst, sizeof(dst))); break; } if (connect(io->in.s, &from, sizeof(from)) != 0) { delete_io(mother, io, io->in.s, IO_ERROR); return; } rstate = io->state; rstate.command = SOCKS_UDPREPLY; if (!rulespermit(io->in.s, &io->rule, &io->state, &io->src, NULL) && !rulespermit(io->in.s, &io->rule, &rstate, NULL, &io->src)) { /* can't send, can't receive; drop it. */ delete_io(mother, io, io->in.s, IO_SRCBLOCK); return; } } io->in.read += r; /* got packet, pull out socks udp header. */ if (string2udpheader(buf, (size_t)r, &header) == NULL) { char badfrom[MAXSOCKADDRSTRING]; /* LINTED pointer casts may be troublesome */ swarnx("%s: bad socks udppacket (length = %d) from %s", function, r, sockaddr2string((struct sockaddr *)&io->in.raddr, badfrom, sizeof(badfrom))); break; } if (header.frag != 0) { char badfrom[MAXSOCKADDRSTRING]; /* LINTED pointer casts may be troublesome */ swarnx("%s: %s: fragmented packet from %s. Not supported", function, protocol2string(io->state.protocol), sockaddr2string((struct sockaddr *)&io->in.raddr, badfrom, sizeof(badfrom))); break; } io->dst = header.host; /* is the packet to be permitted out? */ permit = rulespermit(io->in.s, &io->rule, &io->state, &io->src, &io->dst); /* set r to bytes sent by client sans socks udp header. */ r -= PACKETSIZE_UDP(&header); iolog(&io->rule, &io->state, OPERATION_IO, &io->src, &io->dst, &buf[PACKETSIZE_UDP(&header)], (size_t)r); if (!permit) break; /* LINTED pointer casts may be troublesome */ sockshost2sockaddr(&header.host, (struct sockaddr *)&io->out.raddr); /* LINTED pointer casts may be troublesome */ if ((w = sendto(io->out.s, &buf[PACKETSIZE_UDP(&header)], (size_t)r, lflags, (struct sockaddr *)&io->out.raddr, sizeof(io->out.raddr))) != r) iolog(&io->rule, &io->state, OPERATION_ERROR, &io->src, &io->dst, NULL, 0); io->out.written += MAX(0, w); } /* * Datagram reply from remote present? * We first peek at it so we can find out what address it's from, * then we check rules and then we read the packet out of the buffer. * Reason why we first peek is that if the rule calls libwrap, * libwrap would hang since we'd already read the packet and it * wants to peek itself. * We only peek enough to get the source but this still involves * an extra systemcall. Can we find a better/faster way to do it? */ if (FD_ISSET(io->out.s, rset) && FD_ISSET(io->in.s, wset)) { const int lflags = flags & ~MSG_OOB; struct connectionstate_t state; struct sockaddr from; struct sockshost_t srcsh; char *newbuf; /* MSG_PEEK because of libwrap, see above. */ fromlen = sizeof(from); if ((r = recvfrom(io->out.s, buf, 1, lflags | MSG_PEEK, &from, &fromlen)) == -1) { delete_io(mother, io, io->out.s, r); return; } UDPFROMLENCHECK(io->out.s, fromlen); /* * We can get some problems here in the case that * the client sends a hostname for destination. * If it does it probably means it can't resolve and if * we then send it a ipaddress as source, the client * wont be able to match our source as it's destination, * even if they are the same. * We check for this case specifically, though we only catch * the last case, which may not always be good enough. * We could expand the below check, using addressmatch() * instead, but that need not always be right. * Better safe than sorry for now. */ /* LINTED possible pointer alignment problem */ if (io->dst.atype == SOCKS_ADDR_DOMAIN && sockaddrareeq((struct sockaddr *)&io->out.raddr, &from)) srcsh = io->dst; else sockaddr2sockshost(&from, &srcsh); /* only set temporary here for one replypacket at a time. */ state = io->state; state.command = SOCKS_UDPREPLY; permit = rulespermit(io->out.s, &io->rule, &state, &srcsh, &io->src); /* read the peeked packet out of the buffer. */ fromlen = sizeof(from); if ((r = recvfrom(io->out.s, buf, io->in.sndlowat, lflags, &from, &fromlen)) == -1) { delete_io(mother, io, io->out.s, r); return; } io->out.read += r; iolog(&io->rule, &state, OPERATION_IO, &srcsh, &io->src, buf, (size_t)r); if (!permit) break; /* add socks udpheader. */ /* LINTED pointer casts may be troublesome */ newbuf = udpheader_add(&srcsh, buf, (size_t *)&r, sizeof(buf)); SASSERTX(newbuf == buf); /* * XXX socket must be connected but that should always be the * case for now since binding udp addresses is not supported. */ if ((w = sendto(io->in.s, newbuf, (size_t)r, lflags, NULL, 0)) != r) iolog(&io->rule, &state, OPERATION_ERROR, &srcsh, &io->src, NULL, 0); io->in.written += MAX(0, w); } break; } default: SERRX(io->state.protocol); } /* * Only thing we expect from client's control connection is a eof. * For commands that do not have a controlconnection, we * set descriptor to -1 when receiving others. */ if (io->control.s != -1 && FD_ISSET(io->control.s, rset)) { if ((r = read(io->control.s, buf, sizeof(buf))) <= 0) delete_io(mother, io, io->control.s, r); else { char *unexpected, hmmread[MAXSOCKADDRSTRING]; slog(LOG_NOTICE, "%s/control: %d unexpected bytes: %s", /* LINTED pointer casts may be troublesome */ sockaddr2string((struct sockaddr *)&io->control.raddr, hmmread, sizeof(hmmread)), r, strcheck(unexpected = str2vis(buf, r))); free(unexpected); } } /* don't care what direction/descriptors i/o was done over. */ time(&io->time);}static intio_rw(in, out, bad, buf, flag) struct sockd_io_direction_t *in; struct sockd_io_direction_t *out; int *bad; char *buf; int flag;{ ssize_t r, w; size_t len; if (flag & MSG_OOB) if (sockatmark(in->s) != 1) flag &= ~MSG_OOB; /* we receive oob inline. */ len = flag & MSG_OOB ? 1 : out->sndlowat; if ((r = recv(in->s, buf, len, flag & ~MSG_OOB)) <= 0) { *bad = in->s; return r; } in->read += r; if (flag & MSG_OOB) in->flags |= MSG_OOB; /* read oob data. */ else in->flags &= ~MSG_OOB; /* did not read oob data. */ if ((w = send(out->s, buf, (size_t)r, flag)) != r) { *bad = out->s; return w; } out->written += w; return w;}static voidproctitleupdate(void){ setproctitle("iorelayer: %d/%d", allocated(), SOCKD_IOMAX);}static struct sockd_io_t *io_getset(set) fd_set *set;{ int i; for (i = 0; i < ioc; ++i) if (iov[i].allocated) { if (FD_ISSET(iov[i].in.s, set)) return &iov[i]; if (FD_ISSET(iov[i].out.s, set)) return &iov[i]; switch (iov[i].state.command) { case SOCKS_BIND: case SOCKS_BINDREPLY: if (!iov[i].state.extension.bind) break; /* else: */ /* FALLTHROUGH */ case SOCKS_UDPASSOCIATE: if (FD_ISSET(iov[i].control.s, set)) return &iov[i]; break; default: break; } } return NULL;}static struct sockd_io_t *io_finddescriptor(d) int d;{ int i; for (i = 0; i < ioc; ++i) if (iov[i].allocated) { if (d == iov[i].in.s || d == iov[i].out.s) return &iov[i]; switch (iov[i].state.command) { case SOCKS_BIND: case SOCKS_BINDREPLY: if (!iov[i].state.extension.bind) break; /* else: */ /* FALLTHROUGH */ case SOCKS_UDPASSOCIATE: if (d == iov[i].control.s) return &iov[i]; break; default: break; } } return NULL;}static intio_fillset(set, antiflags) fd_set *set; int antiflags;{ int i, max; FD_ZERO(set); for (i = 0, max = -1; i < ioc; ++i) if (iov[i].allocated) { if (! (antiflags & iov[i].in.flags)) { FD_SET(iov[i].in.s, set); max = MAX(max, iov[i].in.s); } if (! (antiflags & iov[i].out.flags)) { FD_SET(iov[i].out.s, set); max = MAX(max, iov[i].out.s); } switch (iov[i].state.command) { case SOCKS_BIND: case SOCKS_BINDREPLY: if (!iov[i].state.extension.bind) break; /* else: */ /* FALLTHROUGH */ case SOCKS_UDPASSOCIATE: if (! (antiflags & iov[i].control.flags)) { FD_SET(iov[i].control.s, set); max = MAX(max, iov[i].control.s); } break; default: break; } } return max;}static struct timeval *io_gettimeout(timeout) struct timeval *timeout;{ time_t timenow; int i; if (allocated() == 0 || config.timeout.io == 0) return NULL; timeout->tv_sec = config.timeout.io; timeout->tv_usec = 0; time(&timenow); for (i = 0; i < ioc; ++i) if (!iov[i].allocated) continue; else timeout->tv_sec = MAX(0, MIN(timeout->tv_sec, difftime(config.timeout.io, (time_t)difftime(timenow, iov[i].time)))); return timeout;}static struct sockd_io_t *io_gettimedout(void){ int i; time_t timenow; if (config.timeout.io == 0) return NULL; time(&timenow); for (i = 0; i < ioc; ++i) if (!iov[i].allocated) continue; else if (difftime(timenow, iov[i].time) >= config.timeout.io) return &iov[i]; return NULL;}static voidcheckmother(mother, readset) struct sockd_mother_t *mother; fd_set *readset;{ if (mother->s != -1 && FD_ISSET(mother->s, readset)) { FD_CLR(mother->s, readset); if (recv_io(mother->s, NULL) != 0) { close(mother->s); close(mother->ack); mother->s = mother->ack = -1; } else proctitleupdate(); }}/* ARGSUSED */static voidsiginfo(sig) int sig;{ int i; time_t timenow; time(&timenow); for (i = 0; i < ioc; ++i) if (!iov[i].allocated) continue; else { char srcstring[MAXSOCKSHOSTSTRING]; char dststring[MAXSOCKSHOSTSTRING]; slog(LOG_INFO, "%s <-> %s: idle %.0fs", sockshost2string(&iov[i].src, srcstring, sizeof(srcstring)), sockshost2string(&iov[i].dst, dststring, sizeof(dststring)), difftime(timenow, iov[i].time)); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -