Date: Tue, 26 Jan 1999 03:07:16 -0800 (PST) From: wes@bogon.net To: FreeBSD-gnats-submit@FreeBSD.ORG Subject: bin/9696: Updates to natd.c Message-ID: <199901261107.DAA01135@bogon.net>
next in thread | raw e-mail | index | archive | help
>Number: 9696 >Category: bin >Synopsis: Added ability to specify port ranges in natd command line >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Tue Jan 26 03:10:00 PST 1999 >Closed-Date: >Last-Modified: >Originator: Wes Santee >Release: FreeBSD 3.0-RELEASE i386 >Organization: >Environment: N/A. Diff enclosed from natd.c v1.8 >Description: I've added the ability to specify port-ranges with the redirect_port and permanent_link command line options in natd. I've not extensively tested the code, but it appears to be working for me. The new linkspec for redirect_port is of the format: proto targetIP:targetPORT[-targetPORT] [aliasIP:]aliasPORT[-aliasPORT] [remoteIP[:remotePORT[-remotePORT]]] For example: redirect_port tcp 10.0.0.1:2300-2399 3300-3399 will redirect incomming connections on ports 3300-3399 to host 10.0.0.1, ports 2300-2399. The mapping is 1:1 meaning port 3300 maps to 2300, 3301 maps to 2301, etc. The targetPORT range and aliasPORT range need not be the same numerically, but must have the same size. If remotePORT is not specified, it is assumed to be all ports. If remotePORT is specified, it must match the size of targetPORT, or be 0 (all ports). The new linkspec for permanent_link is of the format: proto targetIP:targetPORT[-targetPORT] sourceIP:sourcePORT[-sourcePORT] aliasPORT[-aliasPORT] For example: permanent_link tcp 10.0.0.1:2300-2399 outside:0 3300-3399 will setup 100 permanent links such that packets destined for ports 3300-3399 on this machine from the outside machine (any port) will be sent to ports 2300-2399 on machine 10.0.0.1. As with redirect_port, there is a 1:1 mapping. In addition, the source port range must either be 0 (all ports), or be the same size as the targetPORT range. [N.B.: This linkspec is based off the manpage. It seemed somehow different to me in the code itself, but I left the order of parsing in the code the way it was.] NOTES: - I haven't extensively tested this. It appears to be working on my system, but I'd definately consider this test code. - I'm not even sure these additions are considered "a good thing" so wanting to leave it out entirely may be the best option. - This is my first code submission so take it easy on me, okay? :) Here is a sample natd.conf that I'm using (invoked via the command "natd -config /etc/natd.conf -n xl0" on my system: use_sockets yes unregistered_only yes same_ports yes deny_incoming no ## Allow Direct Play 5 apps to be hostable on the Win95 machine redirect_port tcp kryten:47624 47624 redirect_port udp kryten:47624 47624 redirect_port tcp kryten:2300-2399 2300-2399 redirect_port udp kryten:2300-2399 2300-2399 ## Everything else that comes in goes to 10.0.0.1 redirect_address 10.0.0.1 0.0.0.0 >How-To-Repeat: Apply the patch against v1.8 (by way of the RCS Id) of natd.c and compile. >Fix: *** natd.c.orig Tue Jan 26 02:34:56 1999 --- natd.c Tue Jan 26 02:34:32 1999 *************** *** 9,15 **** * * Ari Suutari <suutari@iki.fi> * ! * $Id: natd.c,v 1.8 1997/12/27 19:31:11 alex Exp $ */ #include <sys/types.h> --- 9,15 ---- * * Ari Suutari <suutari@iki.fi> * ! * $Id: natd.c,v 1.9 1999/01/26 09:17:10 wes Exp wes $ */ #include <sys/types.h> *************** *** 48,53 **** --- 48,72 ---- #define DEFAULT_SERVICE "natd" /* + * Definition of a port range, and macros to deal with values. + * FORMAT: HI 16-bits == first port in range, 0 == all ports. + * LO 16-bits == number of ports in range + * NOTES: - Port values are not stored in network byte order. + */ + + typedef u_long port_range; + + #define GETLOPORT(x) ((x) >> 0x10) + #define GETNUMPORTS(x) ((x) & 0x0000ffff) + #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x))) + + /* Set y to be the low-port value in port_range variable x. */ + #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10)) + + /* Set y to be the number of ports in port_range variable x. */ + #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y)) + + /* * Function prototypes. */ *************** *** 67,74 **** static void SetupAddressRedirect (char* parms); static void StrToAddr (char* str, struct in_addr* addr); static u_short StrToPort (char* str, char* proto); static int StrToProto (char* str); ! static u_short StrToAddrAndPort (char* str, struct in_addr* addr, char* proto); static void ParseArgs (int argc, char** argv); static void FlushPacketBuffer (int fd); --- 86,94 ---- static void SetupAddressRedirect (char* parms); static void StrToAddr (char* str, struct in_addr* addr); static u_short StrToPort (char* str, char* proto); + static int StrToPortRange (char* str, char* proto, port_range *portRange); static int StrToProto (char* str); ! static int StrToAddrAndPortRange (char* str, struct in_addr* addr, char* proto, port_range *portRange); static void ParseArgs (int argc, char** argv); static void FlushPacketBuffer (int fd); *************** *** 894,900 **** { PermanentLink, 0, String, ! "tcp|udp src:port dst:port alias", "define permanent link for incoming connection", "permanent_link", NULL }, --- 914,920 ---- { PermanentLink, 0, String, ! "tcp|udp src:port_range dst:port_range alias_range", "define permanent link for incoming connection", "permanent_link", NULL }, *************** *** 902,910 **** { RedirectPort, 0, String, ! "tcp|udp local_addr:local_port [public_addr:]public_port" ! " [remote_addr[:remote_port]]", ! "redirect a port for incoming traffic", "redirect_port", NULL }, --- 922,930 ---- { RedirectPort, 0, String, ! "tcp|udp local_addr:local_port_range [public_addr:]public_port_range" ! " [remote_addr[:remote_port_range]]", ! "redirect a port (or ports) for incoming traffic", "redirect_port", NULL }, *************** *** 1160,1170 **** char* ptr; struct in_addr srcAddr; struct in_addr dstAddr; ! u_short srcPort; ! u_short dstPort; ! u_short aliasPort; int proto; char* protoName; strcpy (buf, parms); /* --- 1180,1195 ---- char* ptr; struct in_addr srcAddr; struct in_addr dstAddr; ! port_range portRange; ! u_short srcPort = 0; ! u_short dstPort = 0; ! u_short aliasPort = 0; ! u_short numSrcPorts = 0; ! u_short numDstPorts = 0; ! u_short numAliasPorts = 0; int proto; char* protoName; + int i; strcpy (buf, parms); /* *************** *** 1182,1188 **** if (!ptr) errx (1, "permanent_link: missing src address"); ! srcPort = StrToAddrAndPort (ptr, &srcAddr, protoName); /* * Extract destination address. */ --- 1207,1218 ---- if (!ptr) errx (1, "permanent_link: missing src address"); ! if (StrToAddrAndPortRange (ptr, &srcAddr, protoName, &portRange) != 0) ! errx (1, "permanent_link: invalid source port range"); ! ! srcPort = GETLOPORT(portRange); ! numSrcPorts = GETNUMPORTS(portRange); ! /* * Extract destination address. */ *************** *** 1190,1211 **** if (!ptr) errx (1, "permanent_link: missing dst address"); ! dstPort = StrToAddrAndPort (ptr, &dstAddr, protoName); /* ! * Export alias port. */ ptr = strtok (NULL, " \t"); if (!ptr) errx (1, "permanent_link: missing alias port"); ! aliasPort = StrToPort (ptr, protoName); ! PacketAliasPermanentLink (srcAddr, ! srcPort, ! dstAddr, ! dstPort, ! aliasPort, ! proto); } void SetupPortRedirect (char* parms) --- 1220,1268 ---- if (!ptr) errx (1, "permanent_link: missing dst address"); ! if (StrToAddrAndPortRange (ptr, &srcAddr, protoName, &portRange) != 0) ! errx (1, "permanent_link: invalid destination port range"); ! ! dstPort = GETLOPORT(portRange); ! numDstPorts = GETNUMPORTS(portRange); ! /* ! * Export alias port range. */ ptr = strtok (NULL, " \t"); if (!ptr) errx (1, "permanent_link: missing alias port"); ! if (StrToPortRange (ptr, protoName, &portRange) != 0) ! errx (1, "permanent_link: invalid alias port range"); ! ! aliasPort = GETLOPORT(portRange); ! numAliasPorts = GETNUMPORTS(portRange); ! /* ! * Make sure port ranges match up, then add the permanent links. ! */ ! ! if (numSrcPorts != numAliasPorts) ! errx (1, "permanent_link: port ranges must be equal in size"); ! ! /* Destination port range is allowed to be '0' which means all ports. */ ! if (numSrcPorts != numDstPorts && numDstPorts != 1 && dstPort != 0) ! errx (1, "permanent_link: dst port must 0 or equal to src port range in size"); ! ! for (i = 0 ; i < numAliasPorts ; ++i) { ! /* If dstPort is all ports, set it to 0 */ ! u_short dstPortCopy = dstPort + i; ! if (numDstPorts == 1 && dstPort == 0) ! dstPortCopy = 0; ! ! PacketAliasPermanentLink (srcAddr, ! htons(srcPort + i), ! dstAddr, ! htons(dstPortCopy), ! htons(aliasPort + i), ! proto); ! } } void SetupPortRedirect (char* parms) *************** *** 1215,1226 **** struct in_addr localAddr; struct in_addr publicAddr; struct in_addr remoteAddr; ! u_short localPort; ! u_short publicPort; ! u_short remotePort; int proto; char* protoName; char* separator; strcpy (buf, parms); /* --- 1272,1288 ---- struct in_addr localAddr; struct in_addr publicAddr; struct in_addr remoteAddr; ! port_range portRange; ! u_short localPort = 0; ! u_short publicPort = 0; ! u_short remotePort = 0; ! u_short numLocalPorts = 0; ! u_short numPublicPorts = 0; ! u_short numRemotePorts = 0; int proto; char* protoName; char* separator; + int i; strcpy (buf, parms); /* *************** *** 1238,1244 **** if (!ptr) errx (1, "redirect_port: missing local address"); ! localPort = StrToAddrAndPort (ptr, &localAddr, protoName); /* * Extract public port and optinally address. */ --- 1300,1311 ---- if (!ptr) errx (1, "redirect_port: missing local address"); ! if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 ) ! errx (1, "redirect_port: invalid local port range"); ! ! localPort = GETLOPORT(portRange); ! numLocalPorts = GETNUMPORTS(portRange); ! /* * Extract public port and optinally address. */ *************** *** 1247,1291 **** errx (1, "redirect_port: missing public port"); separator = strchr (ptr, ':'); ! if (separator) ! publicPort = StrToAddrAndPort (ptr, &publicAddr, protoName); else { - publicAddr.s_addr = INADDR_ANY; ! publicPort = StrToPort (ptr, protoName); } /* * Extract remote address and optionally port. */ ptr = strtok (NULL, " \t"); if (ptr) { - - separator = strchr (ptr, ':'); if (separator) ! remotePort = StrToAddrAndPort (ptr, ! &remoteAddr, ! protoName); else { ! ! remotePort = 0; StrToAddr (ptr, &remoteAddr); } } else { ! ! remotePort = 0; remoteAddr.s_addr = INADDR_ANY; } ! PacketAliasRedirectPort (localAddr, ! localPort, ! remoteAddr, ! remotePort, ! publicAddr, ! publicPort, ! proto); } void SetupAddressRedirect (char* parms) --- 1314,1380 ---- errx (1, "redirect_port: missing public port"); separator = strchr (ptr, ':'); ! if (separator) { ! if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 ) ! errx (1, "redirect_port: invalid public port range"); ! } else { publicAddr.s_addr = INADDR_ANY; ! if (StrToPortRange (ptr, protoName, &portRange) != 0) ! errx (1, "redirect_port: invalid public port range"); } + publicPort = GETLOPORT(portRange); + numPublicPorts = GETNUMPORTS(portRange); + /* * Extract remote address and optionally port. */ ptr = strtok (NULL, " \t"); if (ptr) { separator = strchr (ptr, ':'); if (separator) ! if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0) ! errx (1, "redirect_port: invalid remote port range"); else { ! SETLOPORT(portRange, 0); ! SETNUMPORTS(portRange, 1); StrToAddr (ptr, &remoteAddr); } } else { ! SETLOPORT(portRange, 0); ! SETNUMPORTS(portRange, 1); remoteAddr.s_addr = INADDR_ANY; } ! remotePort = GETLOPORT(portRange); ! numRemotePorts = GETNUMPORTS(portRange); ! ! /* ! * Make sure port ranges match up, then add the redirect ports. ! */ ! if (numLocalPorts != numPublicPorts) ! errx (1, "redirect_port: port ranges must be equal in size"); ! ! /* Remote port range is allowed to be '0' which means all ports. */ ! if (numRemotePorts != numLocalPorts && numRemotePorts != 1 && remotePort != 0) ! errx (1, "redirect_port: remote port must be 0 or equal to local port range in size"); ! ! for (i = 0 ; i < numPublicPorts ; ++i) { ! /* If remotePort is all ports, set it to 0. */ ! u_short remotePortCopy = remotePort + i; ! if (numRemotePorts == 1 && remotePort == 0) ! remotePortCopy = 0; ! ! PacketAliasRedirectPort (localAddr, ! htons(localPort + i), ! remoteAddr, ! htons(remotePortCopy), ! publicAddr, ! htons(publicPort + i), ! proto); ! } } void SetupAddressRedirect (char* parms) *************** *** 1346,1351 **** --- 1435,1484 ---- return sp->s_port; } + int StrToPortRange (char* str, char* proto, port_range *portRange) + { + char* sep; + struct servent* sp; + char* end; + u_short loPort; + u_short hiPort; + + /* First see if this is a service, return corresponding port if so. */ + sp = getservbyname (str,proto); + if (sp) { + SETLOPORT(*portRange, ntohs(sp->s_port)); + SETNUMPORTS(*portRange, 1); + return 0; + } + + /* Not a service, see if it's a single port or port range. */ + sep = strchr (str, '-'); + if (sep == NULL) { + SETLOPORT(*portRange, strtol(str, &end, 10)); + if (end != str) { + /* Single port. */ + SETNUMPORTS(*portRange, 1); + return 0; + } + + /* Error in port range field. */ + errx (1, "unknown service %s/%s", str, proto); + } + + /* Port range, get the values and sanity check. */ + sscanf (str, "%hu-%hu", &loPort, &hiPort); + SETLOPORT(*portRange, loPort); + SETNUMPORTS(*portRange, 0); /* Error by default */ + if (loPort <= hiPort) + SETNUMPORTS(*portRange, hiPort - loPort + 1); + + if (GETNUMPORTS(*portRange) == 0) + errx (1, "invalid port range %s", str); + + return 0; + } + + int StrToProto (char* str) { if (!strcmp (str, "tcp")) *************** *** 1357,1363 **** errx (1, "unknown protocol %s. Expected tcp or udp", str); } ! u_short StrToAddrAndPort (char* str, struct in_addr* addr, char* proto) { char* ptr; --- 1490,1496 ---- errx (1, "unknown protocol %s. Expected tcp or udp", str); } ! int StrToAddrAndPortRange (char* str, struct in_addr* addr, char* proto, port_range *portRange) { char* ptr; *************** *** 1369,1374 **** ++ptr; StrToAddr (str, addr); ! return StrToPort (ptr, proto); } - --- 1502,1506 ---- ++ptr; StrToAddr (str, addr); ! return StrToPortRange (ptr, proto, portRange); } >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199901261107.DAA01135>