📄 udp.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: udp.c,v 1.110 1999/12/22 09:29:24 karls Exp $";/* ARGSUSED */ssize_tRsendto(s, msg, len, flags, to, tolen) int s; const void *msg; size_t len; int flags; const struct sockaddr *to; socklen_t tolen;{ struct socksfd_t *socksfd; struct sockshost_t host; char *nmsg; size_t nlen; ssize_t n; if (to != NULL && to->sa_family != AF_INET) return sendto(s, msg, len, flags, to, tolen); if (udpsetup(s, to, SOCKS_SEND) != 0) return errno == 0 ? sendto(s, msg, len, flags, to, tolen) : -1; socksfd = socks_getaddr((unsigned int)s); SASSERTX(socksfd != NULL); if (to == NULL) if (socksfd->state.udpconnect) to = &socksfd->connected; else /* best we can do. */ return sendto(s, msg, len, flags, NULL, 0); /* prefix a udp header to the msg */ nlen = len; /* LINTED warning: cast discards 'const' from pointer target type */ if ((nmsg = udpheader_add(fakesockaddr2sockshost(to, &host), (char *)msg, &nlen, 0)) == NULL) { errno = ENOBUFS; return -1; } n = sendto(s, nmsg, nlen, flags, socksfd->state.udpconnect ? NULL : &socksfd->reply, socksfd->state.udpconnect ? 0 : sizeof(socksfd->reply)); n -= nlen - len; free(nmsg); return MAX(-1, n);}ssize_tRrecvfrom(s, buf, len, flags, from, fromlen) int s; void *buf; size_t len; int flags; struct sockaddr *from; socklen_t *fromlen;{ const char *function = "Rrecvfrom()"; struct socksfd_t *socksfd; struct udpheader_t header; char *newbuf; struct sockaddr newfrom; socklen_t newfromlen; size_t newlen; ssize_t n; if (!socks_addrisok((unsigned int)s)) { socks_rmaddr((unsigned int)s); return recvfrom(s, buf, len, flags, from, fromlen); } if (udpsetup(s, from, SOCKS_RECV) != 0) return errno == 0 ? recvfrom(s, buf, len, flags, from, fromlen) : -1; socksfd = socks_getaddr((unsigned int)s); SASSERTX(socksfd != NULL); if (!socksfd->state.protocol.udp) /* assume tcp connection, nothing to do there. */ return recvfrom(s, buf, len, flags, from, fromlen); /* if packet is from socksserver it will be prefixed with a header. */ newlen = len + sizeof(header); if ((newbuf = (char *)malloc(sizeof(*newbuf) * newlen)) == NULL) { errno = ENOBUFS; return -1; } newfromlen = sizeof(newfrom); if ((n = recvfrom(s, newbuf, newlen, flags, &newfrom, &newfromlen)) == -1) { free(newbuf); return n; } SASSERTX(newfromlen > 0); if (sockaddrareeq(&newfrom, &socksfd->reply)) { /* * packet is from socksserver. */ if (string2udpheader(newbuf, (size_t)n, &header) == NULL) { char badfrom[MAXSOCKADDRSTRING]; swarnx("%s: unrecognized socks udppacket from %s", function, sockaddr2string(&newfrom, badfrom, sizeof(badfrom))); errno = EAGAIN; return -1; /* don't know if callee wants to retry. */ } /* if connected udpsocket, only forward from "connected" source. */ if (socksfd->state.udpconnect) { struct sockshost_t host; if (!sockshostareeq(&header.host, fakesockaddr2sockshost(&socksfd->connected, &host))) { char a[MAXSOCKSHOSTSTRING]; char b[MAXSOCKSHOSTSTRING]; /* * We have a problem here ... If we failed to resolve * address we gave to the socksserver and instead gave a * hostname to it, sockshostareeq() will fail unless the server * sends the address it is forwarding from as the sockshost too. * * It is better to place safe than sorry though, so * we have to drop the packet in that case, even if it * is from the correct source since we can not verify it. */ free(newbuf); slog(LOG_DEBUG, "%s: expected udpreply from %s, got it from %s", function, sockshost2string(fakesockaddr2sockshost(&socksfd->connected, &host), a, sizeof(a)), sockshost2string(&header.host, b, sizeof(b))); /* * Not sure what to do now, return error or retry? * Going with returning error for now. */#if 0 if ((p = fcntl(s, F_GETFL, 0)) == -1) return -1; if (p & NONBLOCKING) {#endif errno = EAGAIN; return -1;#if 0 } /* else; assume the best thing is to retry. */ return Rrecvfrom(s, buf, len, flags, from, fromlen);#endif } } /* replace "newfrom" with the address socksserver says packet is from. */ fakesockshost2sockaddr(&header.host, &newfrom); /* callee doesn't get socksheader. */ n -= PACKETSIZE_UDP(&header); SASSERTX(n >= 0); memcpy(buf, &newbuf[PACKETSIZE_UDP(&header)], MIN(len, (size_t)n)); } else /* ordinary udppacket, not from socksserver. */ memcpy(buf, newbuf, MIN(len, (size_t)n)); free(newbuf); if (from != NULL) { *fromlen = MIN(*fromlen, newfromlen); memcpy(from, &newfrom, (size_t)*fromlen); } return MIN(len, (size_t)n);}intudpsetup(s, to, type) int s; const struct sockaddr *to; int type;{ struct socks_t packet; struct socksfd_t socksfd; struct sockaddr_in newto; struct sockshost_t src, dst; socklen_t len; int p; if (!socks_addrisok((unsigned int)s)) socks_rmaddr((unsigned int)s); if (socks_getaddr((unsigned int)s) != NULL) return 0; /* all set up. */ /* * if this socket has not previously been used we need to * make a new connection to the socksserver for it. */ errno = 0; switch (type) { case SOCKS_RECV: /* * problematic, trying to receive on socket not sent on. */ bzero(&newto, sizeof(newto)); newto.sin_family = AF_INET; newto.sin_addr.s_addr = htonl(INADDR_ANY); newto.sin_port = htons(0); /* LINTED pointer casts may be troublesome */ to = (struct sockaddr *)&newto; break; case SOCKS_SEND: if (to == NULL) return -1; /* no address and unknown socket, no idea. */ break; default: SERRX(type); } /* * we need to send the socksserver our address. * First check if the socket already has a name, if so * use that, otherwise assign the name ourselves. */ bzero(&socksfd, sizeof(socksfd)); len = sizeof(socksfd.local); if (getsockname(s, &socksfd.local, &len) != 0) return -1; sockaddr2sockshost(&socksfd.local, &src); fakesockaddr2sockshost(to, &dst); bzero(&packet, sizeof(packet)); packet.version = SOCKS_V5; packet.req.version = packet.version; packet.req.command = SOCKS_UDPASSOCIATE; packet.req.flag |= SOCKS_USECLIENTPORT;/* packet.req.flag |= SOCKS_INTERFACEREQUEST; */ packet.req.host = src; if ((socksfd.control = socket(AF_INET, SOCK_STREAM, 0)) == -1) return -1; if ((socksfd.route = socks_connectroute(socksfd.control, &packet, &src, &dst)) == NULL) { close(socksfd.control); return -1; } /* LINTED pointer casts may be troublesome */ if ((((struct sockaddr_in *)(&socksfd.local))->sin_addr.s_addr == htonl(INADDR_ANY)) /* LINTED pointer casts may be troublesome */ || ((struct sockaddr_in *)(&socksfd.local))->sin_port == htons(0)) { /* * local name not fixed, set it, port may be bound, we need to bind * ip too however. */ /* LINTED pointer casts may be troublesome */ const in_port_t port = ((struct sockaddr_in *)(&socksfd.local))->sin_port; if (port != htons(0)) { /* * port is bound. We will try to unbind and then rebind same port * but now also bind ip address. XXX Dangerous stuff. */ if ((p = socketoptdup(s)) == -1) { close(socksfd.control); return -1; } if (dup2(p, s) == -1) { close(socksfd.control); close(p); return -1; } close(p); } /* * don't have much of an idea on what ip address to use so might as * well use same as tcp connection to socksserver uses. */ len = sizeof(socksfd.local); if (getsockname(socksfd.control, &socksfd.local, &len) != 0) { close(socksfd.control); return -1; } /* LINTED pointer casts may be troublesome */ ((struct sockaddr_in *)&socksfd.local)->sin_port = port; if (bind(s, &socksfd.local, sizeof(socksfd.local)) != 0) { close(socksfd.control); return -1; } if (getsockname(s, &socksfd.local, &len) != 0) { close(socksfd.control); return -1; } sockaddr2sockshost(&socksfd.local, &packet.req.host); }/* packet.req.host.addr.ipv4.s_addr = htonl(INADDR_ANY); *//* packet.req.host.port = htons(0); */ if (socks_negotiate(s, socksfd.control, &packet, socksfd.route) != 0) return -1; socksfd.state.auth = packet.auth; socksfd.state.version = packet.version; socksfd.state.command = SOCKS_UDPASSOCIATE; socksfd.state.protocol.udp = 1; sockshost2sockaddr(&packet.res.host, &socksfd.reply); len = sizeof(socksfd.server); if (getpeername(socksfd.control, &socksfd.server, &len) != 0) { close(socksfd.control); return -1; }#if 0 /* * if the remote server supports interface requests, try to get * the address it's using on our behalf. */ if (packet.res.flag & SOCKS_INTERFACEREQUEST) { struct interfacerequest_t ifreq; ifreq.rsv = 0; ifreq.sub = SOCKS_INTERFACEDATA; ifreq.flag = 0; ifreq.host.atype = SOCKS_ADDR_IPV4; ifreq.host.addr.ipv4 = ((const struct sockaddr_in *)to)->sin_addr; ifreq.host.port = ((const struct sockaddr_in *)to)->sin_port; if (send_interfacerequest(socksfd.control, &ifreq, socksfd.state.version) == 0) { } }#endif if (socks_addaddr((unsigned int)s, &socksfd) == NULL) { close(socksfd.control); errno = ENOBUFS; return -1; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -