6baec531d8
DCC. Debugged and fixed by Rukh (openbsd@rukh.net).
386 lines
10 KiB
Plaintext
386 lines
10 KiB
Plaintext
--- tircproxy.c.orig Fri May 5 06:53:30 2000
|
|
+++ tircproxy.c Thu Apr 25 13:35:39 2002
|
|
@@ -119,6 +119,8 @@
|
|
#endif
|
|
#undef TRANS
|
|
|
|
+#undef RANGEDPORTS
|
|
+
|
|
#if IPF
|
|
# if HAVE_NETINET_IP_NAT_H
|
|
# include <sys/ioctl.h>
|
|
@@ -142,6 +144,15 @@
|
|
# endif
|
|
#endif
|
|
|
|
+#ifdef PF
|
|
+#include <sys/ioctl.h>
|
|
+#include <sys/fcntl.h>
|
|
+#include <net/if.h>
|
|
+#include <net/pfvar.h>
|
|
+#define TRANS 1
|
|
+#define RANGEDPORTS 1
|
|
+#endif
|
|
+
|
|
#ifndef LINUX
|
|
# define LINUX 0
|
|
#endif
|
|
@@ -187,6 +198,11 @@
|
|
|
|
#endif
|
|
|
|
+#ifdef RANGEDPORTS
|
|
+int min_port = IPPORT_HIFIRSTAUTO;
|
|
+int max_port = IPPORT_HILASTAUTO;
|
|
+#endif
|
|
+
|
|
|
|
/* Typedefs.
|
|
*/
|
|
@@ -213,6 +229,10 @@
|
|
static uid_t get_group_id (uid_t uid);
|
|
static int bind_to_port (ipaddr_t bind_ip, short bind_port,
|
|
int backlog, int dlev);
|
|
+#ifdef RANGEDPORTS
|
|
+static int bind_to_ranged_port (ipaddr_t bind_ip, short min_port,
|
|
+ short max_port, int backlog, int dlev);
|
|
+#endif
|
|
static int connect_to_server (struct sockaddr_in addr);
|
|
static void lookup_hostname (struct sockaddr_in *addr, char *hostname,
|
|
int hostlen, int needed);
|
|
@@ -350,8 +370,14 @@
|
|
|
|
/* Parse the command line arguments.
|
|
*/
|
|
- while ((arg = getopt(argc, argv, "ab:d:h?i:o:pq:r:s:t:CDHIKLMNOQRSU")) != EOF)
|
|
+#ifdef RANGEDPORTS
|
|
+ while ((arg = getopt(argc, argv, "ab:d:h?i:m:o:pq:r:s:t:x:CDHIKLMNOQRSU")) != EOF)
|
|
{
|
|
+ char *p;
|
|
+#else
|
|
+ while ((arg = getopt(argc, argv, "ab:d:h?i:o:pq:r:s:t:CDHIKLMNOQRSU")) != EOF)
|
|
+ {
|
|
+#endif
|
|
switch (arg)
|
|
{
|
|
|
|
@@ -375,6 +401,15 @@
|
|
case 'i':
|
|
visible_ip_i = get_ip_addr(optarg);
|
|
break;
|
|
+#ifdef RANGEDPORTS
|
|
+ case 'm':
|
|
+ min_port = strtol(optarg, &p, 10);
|
|
+ if (!*optarg || *p)
|
|
+ usage(argv[0], "Missing min port.");
|
|
+ if (min_port < 0 || min_port > USHRT_MAX)
|
|
+ usage(argv[0], "Invalid min port.");
|
|
+ break;
|
|
+#endif
|
|
case 'o':
|
|
visible_ip_o = get_ip_addr(optarg);
|
|
break;
|
|
@@ -408,6 +443,16 @@
|
|
case 't':
|
|
throttle_seconds = atoi(optarg);
|
|
break;
|
|
+
|
|
+#ifdef RANGEDPORTS
|
|
+ case 'x':
|
|
+ max_port = strtol(optarg, &p, 10);
|
|
+ if (!*optarg || *p)
|
|
+ usage(argv[0], "Missing max port.");
|
|
+ if (max_port < 0 || max_port > USHRT_MAX)
|
|
+ usage(argv[0], "Invalid max port.");
|
|
+ break;
|
|
+#endif
|
|
|
|
case 'C':
|
|
allow_dcc_chat = 0;
|
|
@@ -467,6 +512,11 @@
|
|
break;
|
|
}
|
|
}
|
|
+
|
|
+#ifdef RANGEDPORTS
|
|
+ if (max_port < min_port)
|
|
+ usage(argv[0], "max port can not be smaller than min port.");
|
|
+#endif
|
|
|
|
/* Set a few variables to 'default' values.
|
|
*/
|
|
@@ -684,6 +734,11 @@
|
|
-p Require a valid Unix password for access.\n\
|
|
-q file Read a list of 'quizzes' from the named file.\n");
|
|
#endif
|
|
+#ifdef RANGEDPORTS
|
|
+ fprintf(stderr,"\
|
|
+ -m minport Specify the minimum port to bind incoming DCC connects to.\n\
|
|
+ -x maxport Specify the maxmium port to bind incoming DCC connects to.\n");
|
|
+#endif
|
|
fprintf(stderr,"\
|
|
-a Anonymous mode, hide as much info about the user as possible.\n\
|
|
-r user Run as the specified user in server mode.\n\
|
|
@@ -853,58 +908,146 @@
|
|
return (gid);
|
|
}
|
|
|
|
-
|
|
/* Bind to the specified ip and port.
|
|
*/
|
|
static int bind_to_port(ipaddr_t bind_ip, short bind_port, int backlog, int dlev)
|
|
{
|
|
+ struct sockaddr_in addr;
|
|
+ int sock;
|
|
+
|
|
+ /* Allocate a socket.
|
|
+ */
|
|
+ if ((sock = socket(AF_INET, SOCK_STREAM,
|
|
+ getprotobyname("tcp")->p_proto)) < 0)
|
|
+ {
|
|
+ debug_msg(dlev, LOG_WARNING, "socket(): %d - %.256s", errno, strerror(errno));
|
|
+ return(-1);
|
|
+ }
|
|
+
|
|
+#ifdef TIRC_DEBUG
|
|
+ /* Set the SO_REUSEADDR option for debugging.
|
|
+ */
|
|
+ if (debug_level >= DEBUG_NOFORK) {
|
|
+ int on = 1;
|
|
+
|
|
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ /* Set the address to listen to.
|
|
+ */
|
|
+ memset(&addr, '\0', sizeof(addr));
|
|
+ addr.sin_family = AF_INET;
|
|
+ addr.sin_port = htons(bind_port);
|
|
+ addr.sin_addr.s_addr = bind_ip;
|
|
+
|
|
+ /* Bind our socket to the above address.
|
|
+ */
|
|
+ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
|
+ {
|
|
+ debug_msg(dlev, LOG_WARNING, "bind(): %d - %.256s", errno, strerror(errno));
|
|
+ return(-1);
|
|
+ }
|
|
+
|
|
+ /* Establish a large listen backlog.
|
|
+ */
|
|
+ if (listen(sock, backlog) < 0)
|
|
+ {
|
|
+ debug_msg(dlev, LOG_WARNING, "listen(): %d - %.256s", errno, strerror(errno));
|
|
+ return(-1);
|
|
+ }
|
|
+
|
|
+ return (sock);
|
|
+}
|
|
+
|
|
+#ifdef RANGEDPORTS
|
|
+/* Bind to the specified ip and choose a port in the range of min_port and max_port.
|
|
+*/
|
|
+static int bind_to_ranged_port(ipaddr_t bind_ip, short min_port, short max_port, int backlog, int dlev)
|
|
+
|
|
+{
|
|
struct sockaddr_in addr;
|
|
int sock;
|
|
|
|
- /* Allocate a socket.
|
|
- */
|
|
- if ((sock = socket(AF_INET, SOCK_STREAM,
|
|
- getprotobyname("tcp")->p_proto)) < 0)
|
|
+ int direction = 1;
|
|
+ int count;
|
|
+ short start_port;
|
|
+
|
|
+ if (min_port > max_port)
|
|
{
|
|
- debug_msg(dlev, LOG_WARNING, "socket(): %d - %.256s", errno, strerror(errno));
|
|
- return(-1);
|
|
+ debug_msg(dlev, LOG_WARNING, "min_port > max_port");
|
|
+ return(-1);
|
|
}
|
|
+
|
|
+ count = 1 + max_port - min_port;
|
|
+
|
|
+ start_port = (arc4random() % count) + min_port;
|
|
+
|
|
+ while (count-- > 0) {
|
|
+
|
|
+ /* Allocate a socket.
|
|
+ */
|
|
+ if ((sock = socket(AF_INET, SOCK_STREAM,
|
|
+ getprotobyname("tcp")->p_proto)) < 0)
|
|
+ {
|
|
+ debug_msg(dlev, LOG_WARNING, "socket(): %d - %.256s", errno, strerror(errno));
|
|
+ return(-1);
|
|
+ }
|
|
|
|
#ifdef TIRC_DEBUG
|
|
- /* Set the SO_REUSEADDR option for debugging.
|
|
- */
|
|
- if (debug_level >= DEBUG_NOFORK) {
|
|
- int on = 1;
|
|
+ /* Set the SO_REUSEADDR option for debugging.
|
|
+ */
|
|
+ if (debug_level >= DEBUG_NOFORK) {
|
|
+ int on = 1;
|
|
|
|
- setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
|
|
- }
|
|
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
|
|
+ }
|
|
#endif
|
|
|
|
- /* Set the address to listen to.
|
|
- */
|
|
- memset(&addr, '\0', sizeof(addr));
|
|
- addr.sin_family = AF_INET;
|
|
- addr.sin_port = htons(bind_port);
|
|
- addr.sin_addr.s_addr = bind_ip;
|
|
+ /* Set the address to listen to.
|
|
+ */
|
|
+ memset(&addr, '\0', sizeof(addr));
|
|
+ addr.sin_family = AF_INET;
|
|
+ addr.sin_port = htons(start_port);
|
|
+ addr.sin_addr.s_addr = bind_ip;
|
|
|
|
- /* Bind our socket to the above address.
|
|
- */
|
|
- if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
|
- {
|
|
- debug_msg(dlev, LOG_WARNING, "bind(): %d - %.256s", errno, strerror(errno));
|
|
- return(-1);
|
|
- }
|
|
+ /* Bind our socket to the above address.
|
|
+ */
|
|
+ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) != 0)
|
|
+ {
|
|
+ if (errno != EADDRINUSE)
|
|
+ {
|
|
+ debug_msg(dlev, LOG_WARNING, "bind(): %d - %.256s", errno, strerror(errno));
|
|
+ close(sock);
|
|
+ return(-1);
|
|
+ }
|
|
+ /* It's in use, try the next port */
|
|
+ close(sock);
|
|
|
|
- /* Establish a large listen backlog.
|
|
- */
|
|
- if (listen(sock, backlog) < 0)
|
|
- {
|
|
- debug_msg(dlev, LOG_WARNING, "listen(): %d - %.256s", errno, strerror(errno));
|
|
- return(-1);
|
|
- }
|
|
+ start_port += direction;
|
|
|
|
- return (sock);
|
|
+ if (start_port < min_port)
|
|
+ start_port = max_port;
|
|
+ else if (start_port > max_port)
|
|
+ start_port = min_port;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ /* Establish a large listen backlog.
|
|
+ */
|
|
+ if (listen(sock, backlog) < 0)
|
|
+ {
|
|
+ debug_msg(dlev, LOG_WARNING, "listen(): %d - %.256s", errno, strerror(errno));
|
|
+ close(sock);
|
|
+ return(-1);
|
|
+ }
|
|
+
|
|
+ return (sock);
|
|
+ }
|
|
+ errno = EAGAIN;
|
|
+ return(-1);
|
|
}
|
|
+#endif
|
|
|
|
|
|
/* Connect to the a server.
|
|
@@ -1070,6 +1213,11 @@
|
|
natlookup_t natlook;
|
|
int fd;
|
|
#endif
|
|
+#ifdef PF
|
|
+ struct sockaddr_in ext, gwy;
|
|
+ struct pfioc_natlook natlook;
|
|
+ int fd;
|
|
+#endif
|
|
|
|
/* Give this thing 10 minutes to get started (paranoia).
|
|
*/
|
|
@@ -1166,6 +1314,50 @@
|
|
to_addr.sin_family = AF_INET;
|
|
to_addr.sin_port = htons(ntohs(natlook.nl_realport));
|
|
to_addr.sin_addr.s_addr = get_ip_addr(inet_ntoa(natlook.nl_realip));
|
|
+# else
|
|
+# ifdef PF
|
|
+ to_len = sizeof(ext);
|
|
+ if (getpeername(sock, (struct sockaddr *)&ext, &to_len) == -1)
|
|
+ {
|
|
+ perror("getpeername");
|
|
+ exit(-1);
|
|
+ }
|
|
+
|
|
+ to_len = sizeof(gwy);
|
|
+ if (getsockname(sock, (struct sockaddr *)&gwy, &to_len) == -1)
|
|
+ {
|
|
+ perror("getsockname");
|
|
+ exit(-1);
|
|
+ }
|
|
+
|
|
+ if ((fd = open("/dev/pf", O_RDWR)) == -1) {
|
|
+ perror("open(\"/dev/pf\")");
|
|
+ exit(-1);
|
|
+ }
|
|
+
|
|
+ memset(&natlook, 0, sizeof(struct pfioc_natlook));
|
|
+ natlook.af = AF_INET;
|
|
+ natlook.proto = IPPROTO_TCP;
|
|
+ natlook.direction = PF_OUT; /* s = ext, d = gwy, r = svr */
|
|
+ natlook.saddr.v4.s_addr = ext.sin_addr.s_addr;
|
|
+ natlook.sport = ext.sin_port;
|
|
+ natlook.daddr.v4.s_addr = gwy.sin_addr.s_addr;
|
|
+ natlook.dport = gwy.sin_port;
|
|
+
|
|
+ if (ioctl(fd, DIOCNATLOOK, &natlook) == -1)
|
|
+ {
|
|
+ perror("ioctl");
|
|
+ close(fd);
|
|
+ exit(-1);
|
|
+ }
|
|
+
|
|
+ close(fd);
|
|
+
|
|
+ memset(&to_addr, 0, sizeof(to_addr));
|
|
+ to_addr.sin_family = AF_INET;
|
|
+ to_addr.sin_port = natlook.rdport;
|
|
+ to_addr.sin_addr.s_addr = natlook.rdaddr.v4.s_addr;
|
|
+# endif /* PF */
|
|
# endif /* IFP */
|
|
#endif /* LINUX */
|
|
}
|
|
@@ -2047,9 +2239,15 @@
|
|
** (re: BUGTRAQ, 1998, December 22 & 23)
|
|
*/
|
|
len = 10;
|
|
- while ((listen_sock = bind_to_port((incoming) ? visible_ip_o : visible_ip_i,
|
|
- ((rand() + getpid()) % PPOOL) + 1025,
|
|
+#ifdef RANGEDPORTS
|
|
+ while ((listen_sock = bind_to_ranged_port((incoming) ? visible_ip_o : visible_ip_i,
|
|
+ min_port, max_port,
|
|
1, DEBUG_TRIVIA)) < 0)
|
|
+#else
|
|
+ while ((listen_sock = bind_to_port((incoming) ? visible_ip_o : visible_ip_i,
|
|
+ ((rand() + getpid()) % PPOOL) + 1025,
|
|
+ 1, DEBUG_TRIVIA)) < 0)
|
|
+#endif
|
|
{
|
|
if (--len < 1) {
|
|
debug_msg(0, LOG_ERR, "Failed to bind to port, dropping DCC!");
|