1d17aef79SPedro F. Giffuni /*- 2ead75a59SLuigi Rizzo * Copyright (c) 2002-2003 Luigi Rizzo 3ead75a59SLuigi Rizzo * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp 4ead75a59SLuigi Rizzo * Copyright (c) 1994 Ugen J.S.Antsilevich 5ead75a59SLuigi Rizzo * 6ead75a59SLuigi Rizzo * Idea and grammar partially left from: 7ead75a59SLuigi Rizzo * Copyright (c) 1993 Daniel Boulet 8ead75a59SLuigi Rizzo * 9ead75a59SLuigi Rizzo * Redistribution and use in source forms, with and without modification, 10ead75a59SLuigi Rizzo * are permitted provided that this entire comment appears intact. 11ead75a59SLuigi Rizzo * 12ead75a59SLuigi Rizzo * Redistribution in binary form may occur without any restrictions. 13ead75a59SLuigi Rizzo * Obviously, it would be nice if you gave credit where credit is due 14ead75a59SLuigi Rizzo * but requiring it would be too onerous. 15ead75a59SLuigi Rizzo * 16ead75a59SLuigi Rizzo * This software is provided ``AS IS'' without any warranties of any kind. 17ead75a59SLuigi Rizzo * 18ead75a59SLuigi Rizzo * NEW command line interface for IP firewall facility 19ead75a59SLuigi Rizzo * 20ead75a59SLuigi Rizzo * In-kernel nat support 21ead75a59SLuigi Rizzo */ 22ead75a59SLuigi Rizzo 23ead75a59SLuigi Rizzo #include <sys/types.h> 24ead75a59SLuigi Rizzo #include <sys/socket.h> 25ead75a59SLuigi Rizzo #include <sys/sysctl.h> 26ead75a59SLuigi Rizzo 27ead75a59SLuigi Rizzo #include "ipfw2.h" 28ead75a59SLuigi Rizzo 29ead75a59SLuigi Rizzo #include <ctype.h> 30ead75a59SLuigi Rizzo #include <err.h> 31d6164b77SAlexander V. Chernikov #include <errno.h> 32ead75a59SLuigi Rizzo #include <netdb.h> 33ead75a59SLuigi Rizzo #include <stdio.h> 34ead75a59SLuigi Rizzo #include <stdlib.h> 35ead75a59SLuigi Rizzo #include <string.h> 36ead75a59SLuigi Rizzo #include <sysexits.h> 37ead75a59SLuigi Rizzo 38ead75a59SLuigi Rizzo #include <net/if.h> 39ead75a59SLuigi Rizzo #include <net/if_dl.h> 40ead75a59SLuigi Rizzo #include <net/route.h> /* def. of struct route */ 41ead75a59SLuigi Rizzo #include <netinet/in.h> 42ead75a59SLuigi Rizzo #include <netinet/ip_fw.h> 43ead75a59SLuigi Rizzo #include <arpa/inet.h> 44ead75a59SLuigi Rizzo #include <alias.h> 45ead75a59SLuigi Rizzo 46d6164b77SAlexander V. Chernikov typedef int (nat_cb_t)(struct nat44_cfg_nat *cfg, void *arg); 47d6164b77SAlexander V. Chernikov static void nat_show_cfg(struct nat44_cfg_nat *n, void *arg); 48d6164b77SAlexander V. Chernikov static void nat_show_log(struct nat44_cfg_nat *n, void *arg); 49d6164b77SAlexander V. Chernikov static int nat_show_data(struct nat44_cfg_nat *cfg, void *arg); 50d6164b77SAlexander V. Chernikov static int natname_cmp(const void *a, const void *b); 51d6164b77SAlexander V. Chernikov static int nat_foreach(nat_cb_t *f, void *arg, int sort); 52d6164b77SAlexander V. Chernikov static int nat_get_cmd(char *name, uint16_t cmd, ipfw_obj_header **ooh); 53d6164b77SAlexander V. Chernikov 54ead75a59SLuigi Rizzo static struct _s_x nat_params[] = { 55ead75a59SLuigi Rizzo { "ip", TOK_IP }, 56ead75a59SLuigi Rizzo { "if", TOK_IF }, 57ead75a59SLuigi Rizzo { "log", TOK_ALOG }, 58ead75a59SLuigi Rizzo { "deny_in", TOK_DENY_INC }, 59ead75a59SLuigi Rizzo { "same_ports", TOK_SAME_PORTS }, 60ead75a59SLuigi Rizzo { "unreg_only", TOK_UNREG_ONLY }, 6175b89337SAlexander V. Chernikov { "unreg_cgn", TOK_UNREG_CGN }, 621875bbfeSAndrey V. Elsukov { "skip_global", TOK_SKIP_GLOBAL }, 63ead75a59SLuigi Rizzo { "reset", TOK_RESET_ADDR }, 64ead75a59SLuigi Rizzo { "reverse", TOK_ALIAS_REV }, 65ead75a59SLuigi Rizzo { "proxy_only", TOK_PROXY_ONLY }, 66a08cdb6cSNeel Chauhan { "port_range", TOK_PORT_ALIAS }, 67ead75a59SLuigi Rizzo { "redirect_addr", TOK_REDIR_ADDR }, 68ead75a59SLuigi Rizzo { "redirect_port", TOK_REDIR_PORT }, 69ead75a59SLuigi Rizzo { "redirect_proto", TOK_REDIR_PROTO }, 70*b6c90b90SDamjan Jovanovic { "udp_eim", TOK_UDP_EIM }, 71ead75a59SLuigi Rizzo { NULL, 0 } /* terminator */ 72ead75a59SLuigi Rizzo }; 73ead75a59SLuigi Rizzo 74ead75a59SLuigi Rizzo 75ead75a59SLuigi Rizzo /* 76ead75a59SLuigi Rizzo * Search for interface with name "ifn", and fill n accordingly: 77ead75a59SLuigi Rizzo * 78ead75a59SLuigi Rizzo * n->ip ip address of interface "ifn" 79ead75a59SLuigi Rizzo * n->if_name copy of interface name "ifn" 80ead75a59SLuigi Rizzo */ 81ead75a59SLuigi Rizzo static void 82d6164b77SAlexander V. Chernikov set_addr_dynamic(const char *ifn, struct nat44_cfg_nat *n) 83ead75a59SLuigi Rizzo { 84ead75a59SLuigi Rizzo size_t needed; 85ead75a59SLuigi Rizzo int mib[6]; 86ead75a59SLuigi Rizzo char *buf, *lim, *next; 87ead75a59SLuigi Rizzo struct if_msghdr *ifm; 88ead75a59SLuigi Rizzo struct ifa_msghdr *ifam; 89ead75a59SLuigi Rizzo struct sockaddr_dl *sdl; 90ead75a59SLuigi Rizzo struct sockaddr_in *sin; 91b7684f4bSMarcelo Araujo int ifIndex; 92ead75a59SLuigi Rizzo 93ead75a59SLuigi Rizzo mib[0] = CTL_NET; 94ead75a59SLuigi Rizzo mib[1] = PF_ROUTE; 95ead75a59SLuigi Rizzo mib[2] = 0; 96ead75a59SLuigi Rizzo mib[3] = AF_INET; 97ead75a59SLuigi Rizzo mib[4] = NET_RT_IFLIST; 98ead75a59SLuigi Rizzo mib[5] = 0; 99ead75a59SLuigi Rizzo /* 100ead75a59SLuigi Rizzo * Get interface data. 101ead75a59SLuigi Rizzo */ 102ead75a59SLuigi Rizzo if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) 103ead75a59SLuigi Rizzo err(1, "iflist-sysctl-estimate"); 104ead75a59SLuigi Rizzo buf = safe_calloc(1, needed); 105ead75a59SLuigi Rizzo if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) 106ead75a59SLuigi Rizzo err(1, "iflist-sysctl-get"); 107ead75a59SLuigi Rizzo lim = buf + needed; 108ead75a59SLuigi Rizzo /* 109ead75a59SLuigi Rizzo * Loop through interfaces until one with 110ead75a59SLuigi Rizzo * given name is found. This is done to 111ead75a59SLuigi Rizzo * find correct interface index for routing 112ead75a59SLuigi Rizzo * message processing. 113ead75a59SLuigi Rizzo */ 114ead75a59SLuigi Rizzo ifIndex = 0; 115ead75a59SLuigi Rizzo next = buf; 116ead75a59SLuigi Rizzo while (next < lim) { 117ead75a59SLuigi Rizzo ifm = (struct if_msghdr *)next; 118ead75a59SLuigi Rizzo next += ifm->ifm_msglen; 119ead75a59SLuigi Rizzo if (ifm->ifm_version != RTM_VERSION) { 12056707beeSMark Johnston if (g_co.verbose) 121ead75a59SLuigi Rizzo warnx("routing message version %d " 122ead75a59SLuigi Rizzo "not understood", ifm->ifm_version); 123ead75a59SLuigi Rizzo continue; 124ead75a59SLuigi Rizzo } 125ead75a59SLuigi Rizzo if (ifm->ifm_type == RTM_IFINFO) { 126ead75a59SLuigi Rizzo sdl = (struct sockaddr_dl *)(ifm + 1); 127ead75a59SLuigi Rizzo if (strlen(ifn) == sdl->sdl_nlen && 128ead75a59SLuigi Rizzo strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) { 129ead75a59SLuigi Rizzo ifIndex = ifm->ifm_index; 130ead75a59SLuigi Rizzo break; 131ead75a59SLuigi Rizzo } 132ead75a59SLuigi Rizzo } 133ead75a59SLuigi Rizzo } 134ead75a59SLuigi Rizzo if (!ifIndex) 135ead75a59SLuigi Rizzo errx(1, "unknown interface name %s", ifn); 136ead75a59SLuigi Rizzo /* 137ead75a59SLuigi Rizzo * Get interface address. 138ead75a59SLuigi Rizzo */ 139ead75a59SLuigi Rizzo sin = NULL; 140ead75a59SLuigi Rizzo while (next < lim) { 141ead75a59SLuigi Rizzo ifam = (struct ifa_msghdr *)next; 142ead75a59SLuigi Rizzo next += ifam->ifam_msglen; 143ead75a59SLuigi Rizzo if (ifam->ifam_version != RTM_VERSION) { 14456707beeSMark Johnston if (g_co.verbose) 145ead75a59SLuigi Rizzo warnx("routing message version %d " 146ead75a59SLuigi Rizzo "not understood", ifam->ifam_version); 147ead75a59SLuigi Rizzo continue; 148ead75a59SLuigi Rizzo } 149ead75a59SLuigi Rizzo if (ifam->ifam_type != RTM_NEWADDR) 150ead75a59SLuigi Rizzo break; 151ead75a59SLuigi Rizzo if (ifam->ifam_addrs & RTA_IFA) { 152ead75a59SLuigi Rizzo int i; 153ead75a59SLuigi Rizzo char *cp = (char *)(ifam + 1); 154ead75a59SLuigi Rizzo 155ead75a59SLuigi Rizzo for (i = 1; i < RTA_IFA; i <<= 1) { 156ead75a59SLuigi Rizzo if (ifam->ifam_addrs & i) 157ead75a59SLuigi Rizzo cp += SA_SIZE((struct sockaddr *)cp); 158ead75a59SLuigi Rizzo } 159ead75a59SLuigi Rizzo if (((struct sockaddr *)cp)->sa_family == AF_INET) { 160ead75a59SLuigi Rizzo sin = (struct sockaddr_in *)cp; 161ead75a59SLuigi Rizzo break; 162ead75a59SLuigi Rizzo } 163ead75a59SLuigi Rizzo } 164ead75a59SLuigi Rizzo } 165ead75a59SLuigi Rizzo if (sin == NULL) 1662aa533b9SJohn Baldwin n->ip.s_addr = htonl(INADDR_ANY); 1672aa533b9SJohn Baldwin else 168ead75a59SLuigi Rizzo n->ip = sin->sin_addr; 169ead75a59SLuigi Rizzo strncpy(n->if_name, ifn, IF_NAMESIZE); 170ead75a59SLuigi Rizzo 171ead75a59SLuigi Rizzo free(buf); 172ead75a59SLuigi Rizzo } 173ead75a59SLuigi Rizzo 174ead75a59SLuigi Rizzo /* 175ead75a59SLuigi Rizzo * XXX - The following functions, macros and definitions come from natd.c: 176ead75a59SLuigi Rizzo * it would be better to move them outside natd.c, in a file 177ead75a59SLuigi Rizzo * (redirect_support.[ch]?) shared by ipfw and natd, but for now i can live 178ead75a59SLuigi Rizzo * with it. 179ead75a59SLuigi Rizzo */ 180ead75a59SLuigi Rizzo 181ead75a59SLuigi Rizzo /* 182ead75a59SLuigi Rizzo * Definition of a port range, and macros to deal with values. 183ead75a59SLuigi Rizzo * FORMAT: HI 16-bits == first port in range, 0 == all ports. 184ead75a59SLuigi Rizzo * LO 16-bits == number of ports in range 185ead75a59SLuigi Rizzo * NOTES: - Port values are not stored in network byte order. 186ead75a59SLuigi Rizzo */ 187ead75a59SLuigi Rizzo 188ead75a59SLuigi Rizzo #define port_range u_long 189ead75a59SLuigi Rizzo 190ead75a59SLuigi Rizzo #define GETLOPORT(x) ((x) >> 0x10) 191ead75a59SLuigi Rizzo #define GETNUMPORTS(x) ((x) & 0x0000ffff) 192ead75a59SLuigi Rizzo #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x))) 193ead75a59SLuigi Rizzo 194ead75a59SLuigi Rizzo /* Set y to be the low-port value in port_range variable x. */ 195ead75a59SLuigi Rizzo #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10)) 196ead75a59SLuigi Rizzo 197ead75a59SLuigi Rizzo /* Set y to be the number of ports in port_range variable x. */ 198ead75a59SLuigi Rizzo #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y)) 199ead75a59SLuigi Rizzo 200ead75a59SLuigi Rizzo static void 201ead75a59SLuigi Rizzo StrToAddr (const char* str, struct in_addr* addr) 202ead75a59SLuigi Rizzo { 203ead75a59SLuigi Rizzo struct hostent* hp; 204ead75a59SLuigi Rizzo 205ead75a59SLuigi Rizzo if (inet_aton (str, addr)) 206ead75a59SLuigi Rizzo return; 207ead75a59SLuigi Rizzo 208ead75a59SLuigi Rizzo hp = gethostbyname (str); 209ead75a59SLuigi Rizzo if (!hp) 210ead75a59SLuigi Rizzo errx (1, "unknown host %s", str); 211ead75a59SLuigi Rizzo 212ead75a59SLuigi Rizzo memcpy (addr, hp->h_addr, sizeof (struct in_addr)); 213ead75a59SLuigi Rizzo } 214ead75a59SLuigi Rizzo 215ead75a59SLuigi Rizzo static int 216ead75a59SLuigi Rizzo StrToPortRange (const char* str, const char* proto, port_range *portRange) 217ead75a59SLuigi Rizzo { 218ead75a59SLuigi Rizzo char* sep; 219ead75a59SLuigi Rizzo struct servent* sp; 220ead75a59SLuigi Rizzo char* end; 221ead75a59SLuigi Rizzo u_short loPort; 222ead75a59SLuigi Rizzo u_short hiPort; 223ead75a59SLuigi Rizzo 224ead75a59SLuigi Rizzo /* First see if this is a service, return corresponding port if so. */ 225ead75a59SLuigi Rizzo sp = getservbyname (str,proto); 226ead75a59SLuigi Rizzo if (sp) { 227ead75a59SLuigi Rizzo SETLOPORT(*portRange, ntohs(sp->s_port)); 228ead75a59SLuigi Rizzo SETNUMPORTS(*portRange, 1); 229ead75a59SLuigi Rizzo return 0; 230ead75a59SLuigi Rizzo } 231ead75a59SLuigi Rizzo 232ead75a59SLuigi Rizzo /* Not a service, see if it's a single port or port range. */ 233ead75a59SLuigi Rizzo sep = strchr (str, '-'); 234ead75a59SLuigi Rizzo if (sep == NULL) { 235ead75a59SLuigi Rizzo SETLOPORT(*portRange, strtol(str, &end, 10)); 236ead75a59SLuigi Rizzo if (end != str) { 237ead75a59SLuigi Rizzo /* Single port. */ 238ead75a59SLuigi Rizzo SETNUMPORTS(*portRange, 1); 239ead75a59SLuigi Rizzo return 0; 240ead75a59SLuigi Rizzo } 241ead75a59SLuigi Rizzo 242ead75a59SLuigi Rizzo /* Error in port range field. */ 243ead75a59SLuigi Rizzo errx (EX_DATAERR, "%s/%s: unknown service", str, proto); 244ead75a59SLuigi Rizzo } 245ead75a59SLuigi Rizzo 246ead75a59SLuigi Rizzo /* Port range, get the values and sanity check. */ 247ead75a59SLuigi Rizzo sscanf (str, "%hu-%hu", &loPort, &hiPort); 248ead75a59SLuigi Rizzo SETLOPORT(*portRange, loPort); 249ead75a59SLuigi Rizzo SETNUMPORTS(*portRange, 0); /* Error by default */ 250ead75a59SLuigi Rizzo if (loPort <= hiPort) 251ead75a59SLuigi Rizzo SETNUMPORTS(*portRange, hiPort - loPort + 1); 252ead75a59SLuigi Rizzo 253ead75a59SLuigi Rizzo if (GETNUMPORTS(*portRange) == 0) 254ead75a59SLuigi Rizzo errx (EX_DATAERR, "invalid port range %s", str); 255ead75a59SLuigi Rizzo 256ead75a59SLuigi Rizzo return 0; 257ead75a59SLuigi Rizzo } 258ead75a59SLuigi Rizzo 259ead75a59SLuigi Rizzo static int 260ead75a59SLuigi Rizzo StrToProto (const char* str) 261ead75a59SLuigi Rizzo { 262ead75a59SLuigi Rizzo if (!strcmp (str, "tcp")) 263ead75a59SLuigi Rizzo return IPPROTO_TCP; 264ead75a59SLuigi Rizzo 265ead75a59SLuigi Rizzo if (!strcmp (str, "udp")) 266ead75a59SLuigi Rizzo return IPPROTO_UDP; 267ead75a59SLuigi Rizzo 26837ce2656SPaolo Pisati if (!strcmp (str, "sctp")) 26937ce2656SPaolo Pisati return IPPROTO_SCTP; 27037ce2656SPaolo Pisati errx (EX_DATAERR, "unknown protocol %s. Expected sctp, tcp or udp", str); 271ead75a59SLuigi Rizzo } 272ead75a59SLuigi Rizzo 273ead75a59SLuigi Rizzo static int 274ead75a59SLuigi Rizzo StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, 275ead75a59SLuigi Rizzo port_range *portRange) 276ead75a59SLuigi Rizzo { 277ead75a59SLuigi Rizzo char* ptr; 278ead75a59SLuigi Rizzo 279ead75a59SLuigi Rizzo ptr = strchr (str, ':'); 280ead75a59SLuigi Rizzo if (!ptr) 281ead75a59SLuigi Rizzo errx (EX_DATAERR, "%s is missing port number", str); 282ead75a59SLuigi Rizzo 283ead75a59SLuigi Rizzo *ptr = '\0'; 284ead75a59SLuigi Rizzo ++ptr; 285ead75a59SLuigi Rizzo 286ead75a59SLuigi Rizzo StrToAddr (str, addr); 287ead75a59SLuigi Rizzo return StrToPortRange (ptr, proto, portRange); 288ead75a59SLuigi Rizzo } 289ead75a59SLuigi Rizzo 290ead75a59SLuigi Rizzo /* End of stuff taken from natd.c. */ 291ead75a59SLuigi Rizzo 292ead75a59SLuigi Rizzo /* 293ead75a59SLuigi Rizzo * The next 3 functions add support for the addr, port and proto redirect and 294ead75a59SLuigi Rizzo * their logic is loosely based on SetupAddressRedirect(), SetupPortRedirect() 295ead75a59SLuigi Rizzo * and SetupProtoRedirect() from natd.c. 296ead75a59SLuigi Rizzo * 297ead75a59SLuigi Rizzo * Every setup_* function fills at least one redirect entry 298d6164b77SAlexander V. Chernikov * (struct nat44_cfg_redir) and zero or more server pool entry 299d6164b77SAlexander V. Chernikov * (struct nat44_cfg_spool) in buf. 300ead75a59SLuigi Rizzo * 301ead75a59SLuigi Rizzo * The format of data in buf is: 302ead75a59SLuigi Rizzo * 303d6164b77SAlexander V. Chernikov * nat44_cfg_nat nat44_cfg_redir nat44_cfg_spool ...... nat44_cfg_spool 304ead75a59SLuigi Rizzo * 305ead75a59SLuigi Rizzo * ------------------------------------- ------------ 306d6164b77SAlexander V. Chernikov * | | .....X ..... | | | | ..... 307ead75a59SLuigi Rizzo * ------------------------------------- ...... ------------ 308ead75a59SLuigi Rizzo * ^ 309ead75a59SLuigi Rizzo * spool_cnt n=0 ...... n=(X-1) 310ead75a59SLuigi Rizzo * 311ead75a59SLuigi Rizzo * len points to the amount of available space in buf 312ead75a59SLuigi Rizzo * space counts the memory consumed by every function 313ead75a59SLuigi Rizzo * 314ead75a59SLuigi Rizzo * XXX - Every function get all the argv params so it 315ead75a59SLuigi Rizzo * has to check, in optional parameters, that the next 316ead75a59SLuigi Rizzo * args is a valid option for the redir entry and not 317ead75a59SLuigi Rizzo * another token. Only redir_port and redir_proto are 318ead75a59SLuigi Rizzo * affected by this. 319ead75a59SLuigi Rizzo */ 320ead75a59SLuigi Rizzo 321ead75a59SLuigi Rizzo static int 322d5a80549SGleb Smirnoff estimate_redir_addr(int *ac, char ***av) 323ead75a59SLuigi Rizzo { 324d6164b77SAlexander V. Chernikov size_t space = sizeof(struct nat44_cfg_redir); 325ce972082SGleb Smirnoff char *sep = **av; 326ce972082SGleb Smirnoff u_int c = 0; 327ead75a59SLuigi Rizzo 3286a7bb02dSLuigi Rizzo (void)ac; /* UNUSED */ 329ce972082SGleb Smirnoff while ((sep = strchr(sep, ',')) != NULL) { 330ce972082SGleb Smirnoff c++; 331ce972082SGleb Smirnoff sep++; 332ead75a59SLuigi Rizzo } 333d5a80549SGleb Smirnoff 334ce972082SGleb Smirnoff if (c > 0) 335ce972082SGleb Smirnoff c++; 336ce972082SGleb Smirnoff 337d6164b77SAlexander V. Chernikov space += c * sizeof(struct nat44_cfg_spool); 338ce972082SGleb Smirnoff 339ead75a59SLuigi Rizzo return (space); 340ead75a59SLuigi Rizzo } 341ead75a59SLuigi Rizzo 342ead75a59SLuigi Rizzo static int 343d5a80549SGleb Smirnoff setup_redir_addr(char *buf, int *ac, char ***av) 344ead75a59SLuigi Rizzo { 345d6164b77SAlexander V. Chernikov struct nat44_cfg_redir *r; 346d5a80549SGleb Smirnoff char *sep; 347d5a80549SGleb Smirnoff size_t space; 348d5a80549SGleb Smirnoff 349d6164b77SAlexander V. Chernikov r = (struct nat44_cfg_redir *)buf; 350d5a80549SGleb Smirnoff r->mode = REDIR_ADDR; 351d6164b77SAlexander V. Chernikov /* Skip nat44_cfg_redir at beginning of buf. */ 352d6164b77SAlexander V. Chernikov buf = &buf[sizeof(struct nat44_cfg_redir)]; 353d6164b77SAlexander V. Chernikov space = sizeof(struct nat44_cfg_redir); 354d5a80549SGleb Smirnoff 355d5a80549SGleb Smirnoff /* Extract local address. */ 3568d913bf8SGleb Smirnoff if (strchr(**av, ',') != NULL) { 357d6164b77SAlexander V. Chernikov struct nat44_cfg_spool *spool; 358d5a80549SGleb Smirnoff 359d5a80549SGleb Smirnoff /* Setup LSNAT server pool. */ 360d5a80549SGleb Smirnoff r->laddr.s_addr = INADDR_NONE; 3618d913bf8SGleb Smirnoff sep = strtok(**av, ","); 362d5a80549SGleb Smirnoff while (sep != NULL) { 363d6164b77SAlexander V. Chernikov spool = (struct nat44_cfg_spool *)buf; 364d6164b77SAlexander V. Chernikov space += sizeof(struct nat44_cfg_spool); 365d5a80549SGleb Smirnoff StrToAddr(sep, &spool->addr); 366d5a80549SGleb Smirnoff spool->port = ~0; 367d5a80549SGleb Smirnoff r->spool_cnt++; 368d6164b77SAlexander V. Chernikov /* Point to the next possible nat44_cfg_spool. */ 369d6164b77SAlexander V. Chernikov buf = &buf[sizeof(struct nat44_cfg_spool)]; 370d5a80549SGleb Smirnoff sep = strtok(NULL, ","); 371d5a80549SGleb Smirnoff } 372d5a80549SGleb Smirnoff } else 373d5a80549SGleb Smirnoff StrToAddr(**av, &r->laddr); 374d5a80549SGleb Smirnoff (*av)++; (*ac)--; 375d5a80549SGleb Smirnoff 376d5a80549SGleb Smirnoff /* Extract public address. */ 377d5a80549SGleb Smirnoff StrToAddr(**av, &r->paddr); 378d5a80549SGleb Smirnoff (*av)++; (*ac)--; 379d5a80549SGleb Smirnoff 380d5a80549SGleb Smirnoff return (space); 381d5a80549SGleb Smirnoff } 382d5a80549SGleb Smirnoff 383d5a80549SGleb Smirnoff static int 384d5a80549SGleb Smirnoff estimate_redir_port(int *ac, char ***av) 385d5a80549SGleb Smirnoff { 386d6164b77SAlexander V. Chernikov size_t space = sizeof(struct nat44_cfg_redir); 387ce972082SGleb Smirnoff char *sep = **av; 388ce972082SGleb Smirnoff u_int c = 0; 389d5a80549SGleb Smirnoff 3906a7bb02dSLuigi Rizzo (void)ac; /* UNUSED */ 391ce972082SGleb Smirnoff while ((sep = strchr(sep, ',')) != NULL) { 392ce972082SGleb Smirnoff c++; 393ce972082SGleb Smirnoff sep++; 394d5a80549SGleb Smirnoff } 395d5a80549SGleb Smirnoff 396ce972082SGleb Smirnoff if (c > 0) 397ce972082SGleb Smirnoff c++; 398ce972082SGleb Smirnoff 399d6164b77SAlexander V. Chernikov space += c * sizeof(struct nat44_cfg_spool); 400ce972082SGleb Smirnoff 401d5a80549SGleb Smirnoff return (space); 402d5a80549SGleb Smirnoff } 403d5a80549SGleb Smirnoff 404d5a80549SGleb Smirnoff static int 405d5a80549SGleb Smirnoff setup_redir_port(char *buf, int *ac, char ***av) 406d5a80549SGleb Smirnoff { 407d6164b77SAlexander V. Chernikov struct nat44_cfg_redir *r; 408d5a80549SGleb Smirnoff char *sep, *protoName, *lsnat = NULL; 409d5a80549SGleb Smirnoff size_t space; 410ead75a59SLuigi Rizzo u_short numLocalPorts; 411ead75a59SLuigi Rizzo port_range portRange; 412ead75a59SLuigi Rizzo 413ead75a59SLuigi Rizzo numLocalPorts = 0; 414ead75a59SLuigi Rizzo 415d6164b77SAlexander V. Chernikov r = (struct nat44_cfg_redir *)buf; 416ead75a59SLuigi Rizzo r->mode = REDIR_PORT; 417d6164b77SAlexander V. Chernikov /* Skip nat44_cfg_redir at beginning of buf. */ 418d6164b77SAlexander V. Chernikov buf = &buf[sizeof(struct nat44_cfg_redir)]; 419d6164b77SAlexander V. Chernikov space = sizeof(struct nat44_cfg_redir); 420d5a80549SGleb Smirnoff 421ead75a59SLuigi Rizzo /* 422ead75a59SLuigi Rizzo * Extract protocol. 423ead75a59SLuigi Rizzo */ 424d5a80549SGleb Smirnoff r->proto = StrToProto(**av); 425d5a80549SGleb Smirnoff protoName = **av; 426d5a80549SGleb Smirnoff (*av)++; (*ac)--; 427ead75a59SLuigi Rizzo 428ead75a59SLuigi Rizzo /* 429ead75a59SLuigi Rizzo * Extract local address. 430ead75a59SLuigi Rizzo */ 4313dedcef7SKevin Lo if (strchr(**av, ',') != NULL) { 432ead75a59SLuigi Rizzo r->laddr.s_addr = INADDR_NONE; 433ead75a59SLuigi Rizzo r->lport = ~0; 434ead75a59SLuigi Rizzo numLocalPorts = 1; 435d5a80549SGleb Smirnoff lsnat = **av; 436ead75a59SLuigi Rizzo } else { 43737ce2656SPaolo Pisati /* 43837ce2656SPaolo Pisati * The sctp nat does not allow the port numbers to be mapped to 43937ce2656SPaolo Pisati * new port numbers. Therefore, no ports are to be specified 44037ce2656SPaolo Pisati * in the target port field. 44137ce2656SPaolo Pisati */ 44237ce2656SPaolo Pisati if (r->proto == IPPROTO_SCTP) { 443d5a80549SGleb Smirnoff if (strchr(**av, ':')) 44437ce2656SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 445d5a80549SGleb Smirnoff "port numbers do not change in sctp, so do " 446d5a80549SGleb Smirnoff "not specify them as part of the target"); 44737ce2656SPaolo Pisati else 448d5a80549SGleb Smirnoff StrToAddr(**av, &r->laddr); 44937ce2656SPaolo Pisati } else { 450d5a80549SGleb Smirnoff if (StrToAddrAndPortRange(**av, &r->laddr, protoName, 451ead75a59SLuigi Rizzo &portRange) != 0) 452ead75a59SLuigi Rizzo errx(EX_DATAERR, "redirect_port: " 453ead75a59SLuigi Rizzo "invalid local port range"); 454ead75a59SLuigi Rizzo 455ead75a59SLuigi Rizzo r->lport = GETLOPORT(portRange); 456ead75a59SLuigi Rizzo numLocalPorts = GETNUMPORTS(portRange); 457ead75a59SLuigi Rizzo } 45837ce2656SPaolo Pisati } 459d5a80549SGleb Smirnoff (*av)++; (*ac)--; 460ead75a59SLuigi Rizzo 461ead75a59SLuigi Rizzo /* 462ead75a59SLuigi Rizzo * Extract public port and optionally address. 463ead75a59SLuigi Rizzo */ 4643dedcef7SKevin Lo if (strchr(**av, ':') != NULL) { 465d5a80549SGleb Smirnoff if (StrToAddrAndPortRange(**av, &r->paddr, protoName, 466ead75a59SLuigi Rizzo &portRange) != 0) 467ead75a59SLuigi Rizzo errx(EX_DATAERR, "redirect_port: " 468ead75a59SLuigi Rizzo "invalid public port range"); 469ead75a59SLuigi Rizzo } else { 470ead75a59SLuigi Rizzo r->paddr.s_addr = INADDR_ANY; 471d5a80549SGleb Smirnoff if (StrToPortRange(**av, protoName, &portRange) != 0) 472ead75a59SLuigi Rizzo errx(EX_DATAERR, "redirect_port: " 473ead75a59SLuigi Rizzo "invalid public port range"); 474ead75a59SLuigi Rizzo } 475ead75a59SLuigi Rizzo 476ead75a59SLuigi Rizzo r->pport = GETLOPORT(portRange); 47737ce2656SPaolo Pisati if (r->proto == IPPROTO_SCTP) { /* so the logic below still works */ 47837ce2656SPaolo Pisati numLocalPorts = GETNUMPORTS(portRange); 47937ce2656SPaolo Pisati r->lport = r->pport; 48037ce2656SPaolo Pisati } 481ead75a59SLuigi Rizzo r->pport_cnt = GETNUMPORTS(portRange); 482d5a80549SGleb Smirnoff (*av)++; (*ac)--; 483ead75a59SLuigi Rizzo 484ead75a59SLuigi Rizzo /* 485ead75a59SLuigi Rizzo * Extract remote address and optionally port. 486ead75a59SLuigi Rizzo */ 487ead75a59SLuigi Rizzo /* 488ce972082SGleb Smirnoff * NB: isdigit(**av) => we've to check that next parameter is really an 489ead75a59SLuigi Rizzo * option for this redirect entry, else stop here processing arg[cv]. 490ead75a59SLuigi Rizzo */ 491ce972082SGleb Smirnoff if (*ac != 0 && isdigit(***av)) { 4923dedcef7SKevin Lo if (strchr(**av, ':') != NULL) { 493d5a80549SGleb Smirnoff if (StrToAddrAndPortRange(**av, &r->raddr, protoName, 494ead75a59SLuigi Rizzo &portRange) != 0) 495ead75a59SLuigi Rizzo errx(EX_DATAERR, "redirect_port: " 496ead75a59SLuigi Rizzo "invalid remote port range"); 497ead75a59SLuigi Rizzo } else { 498ead75a59SLuigi Rizzo SETLOPORT(portRange, 0); 499ead75a59SLuigi Rizzo SETNUMPORTS(portRange, 1); 500d5a80549SGleb Smirnoff StrToAddr(**av, &r->raddr); 501ead75a59SLuigi Rizzo } 502d5a80549SGleb Smirnoff (*av)++; (*ac)--; 503ead75a59SLuigi Rizzo } else { 504ead75a59SLuigi Rizzo SETLOPORT(portRange, 0); 505ead75a59SLuigi Rizzo SETNUMPORTS(portRange, 1); 506ead75a59SLuigi Rizzo r->raddr.s_addr = INADDR_ANY; 507ead75a59SLuigi Rizzo } 508ead75a59SLuigi Rizzo r->rport = GETLOPORT(portRange); 509ead75a59SLuigi Rizzo r->rport_cnt = GETNUMPORTS(portRange); 510ead75a59SLuigi Rizzo 511ead75a59SLuigi Rizzo /* 512ead75a59SLuigi Rizzo * Make sure port ranges match up, then add the redirect ports. 513ead75a59SLuigi Rizzo */ 514ead75a59SLuigi Rizzo if (numLocalPorts != r->pport_cnt) 515ead75a59SLuigi Rizzo errx(EX_DATAERR, "redirect_port: " 516ead75a59SLuigi Rizzo "port ranges must be equal in size"); 517ead75a59SLuigi Rizzo 518ead75a59SLuigi Rizzo /* Remote port range is allowed to be '0' which means all ports. */ 519ead75a59SLuigi Rizzo if (r->rport_cnt != numLocalPorts && 520ead75a59SLuigi Rizzo (r->rport_cnt != 1 || r->rport != 0)) 521ead75a59SLuigi Rizzo errx(EX_DATAERR, "redirect_port: remote port must" 522ead75a59SLuigi Rizzo "be 0 or equal to local port range in size"); 523ead75a59SLuigi Rizzo 524d5a80549SGleb Smirnoff /* Setup LSNAT server pool. */ 525d5a80549SGleb Smirnoff if (lsnat != NULL) { 526d6164b77SAlexander V. Chernikov struct nat44_cfg_spool *spool; 527d5a80549SGleb Smirnoff 528d5a80549SGleb Smirnoff sep = strtok(lsnat, ","); 529ead75a59SLuigi Rizzo while (sep != NULL) { 530d6164b77SAlexander V. Chernikov spool = (struct nat44_cfg_spool *)buf; 531d6164b77SAlexander V. Chernikov space += sizeof(struct nat44_cfg_spool); 53237ce2656SPaolo Pisati /* 533d5a80549SGleb Smirnoff * The sctp nat does not allow the port numbers to 534d5a80549SGleb Smirnoff * be mapped to new port numbers. Therefore, no ports 535d5a80549SGleb Smirnoff * are to be specified in the target port field. 53637ce2656SPaolo Pisati */ 53737ce2656SPaolo Pisati if (r->proto == IPPROTO_SCTP) { 53837ce2656SPaolo Pisati if (strchr (sep, ':')) { 53937ce2656SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 54037ce2656SPaolo Pisati "port numbers do not change in " 54137ce2656SPaolo Pisati "sctp, so do not specify them as " 54237ce2656SPaolo Pisati "part of the target"); 54337ce2656SPaolo Pisati } else { 544d5a80549SGleb Smirnoff StrToAddr(sep, &spool->addr); 545d5a80549SGleb Smirnoff spool->port = r->pport; 54637ce2656SPaolo Pisati } 54737ce2656SPaolo Pisati } else { 548d5a80549SGleb Smirnoff if (StrToAddrAndPortRange(sep, &spool->addr, 54937ce2656SPaolo Pisati protoName, &portRange) != 0) 550ead75a59SLuigi Rizzo errx(EX_DATAERR, "redirect_port:" 551ead75a59SLuigi Rizzo "invalid local port range"); 552ead75a59SLuigi Rizzo if (GETNUMPORTS(portRange) != 1) 55337ce2656SPaolo Pisati errx(EX_DATAERR, "redirect_port: " 55437ce2656SPaolo Pisati "local port must be single in " 55537ce2656SPaolo Pisati "this context"); 556d5a80549SGleb Smirnoff spool->port = GETLOPORT(portRange); 55737ce2656SPaolo Pisati } 558ead75a59SLuigi Rizzo r->spool_cnt++; 559d6164b77SAlexander V. Chernikov /* Point to the next possible nat44_cfg_spool. */ 560d6164b77SAlexander V. Chernikov buf = &buf[sizeof(struct nat44_cfg_spool)]; 561ead75a59SLuigi Rizzo sep = strtok(NULL, ","); 562ead75a59SLuigi Rizzo } 563ead75a59SLuigi Rizzo } 564d5a80549SGleb Smirnoff 565ead75a59SLuigi Rizzo return (space); 566ead75a59SLuigi Rizzo } 567ead75a59SLuigi Rizzo 568ead75a59SLuigi Rizzo static int 569d5a80549SGleb Smirnoff setup_redir_proto(char *buf, int *ac, char ***av) 570ead75a59SLuigi Rizzo { 571d6164b77SAlexander V. Chernikov struct nat44_cfg_redir *r; 572d5a80549SGleb Smirnoff struct protoent *protoent; 573d5a80549SGleb Smirnoff size_t space; 574ead75a59SLuigi Rizzo 575d6164b77SAlexander V. Chernikov r = (struct nat44_cfg_redir *)buf; 576ead75a59SLuigi Rizzo r->mode = REDIR_PROTO; 577d6164b77SAlexander V. Chernikov /* Skip nat44_cfg_redir at beginning of buf. */ 578d6164b77SAlexander V. Chernikov buf = &buf[sizeof(struct nat44_cfg_redir)]; 579d6164b77SAlexander V. Chernikov space = sizeof(struct nat44_cfg_redir); 580d5a80549SGleb Smirnoff 581ead75a59SLuigi Rizzo /* 582ead75a59SLuigi Rizzo * Extract protocol. 583ead75a59SLuigi Rizzo */ 584d5a80549SGleb Smirnoff protoent = getprotobyname(**av); 585ead75a59SLuigi Rizzo if (protoent == NULL) 586d5a80549SGleb Smirnoff errx(EX_DATAERR, "redirect_proto: unknown protocol %s", **av); 587ead75a59SLuigi Rizzo else 588ead75a59SLuigi Rizzo r->proto = protoent->p_proto; 589ead75a59SLuigi Rizzo 590d5a80549SGleb Smirnoff (*av)++; (*ac)--; 591ead75a59SLuigi Rizzo 592ead75a59SLuigi Rizzo /* 593ead75a59SLuigi Rizzo * Extract local address. 594ead75a59SLuigi Rizzo */ 595d5a80549SGleb Smirnoff StrToAddr(**av, &r->laddr); 596ead75a59SLuigi Rizzo 597d5a80549SGleb Smirnoff (*av)++; (*ac)--; 598ead75a59SLuigi Rizzo 599ead75a59SLuigi Rizzo /* 600ead75a59SLuigi Rizzo * Extract optional public address. 601ead75a59SLuigi Rizzo */ 602d5a80549SGleb Smirnoff if (*ac == 0) { 603ead75a59SLuigi Rizzo r->paddr.s_addr = INADDR_ANY; 604ead75a59SLuigi Rizzo r->raddr.s_addr = INADDR_ANY; 605ead75a59SLuigi Rizzo } else { 606ead75a59SLuigi Rizzo /* see above in setup_redir_port() */ 607ce972082SGleb Smirnoff if (isdigit(***av)) { 608d5a80549SGleb Smirnoff StrToAddr(**av, &r->paddr); 609d5a80549SGleb Smirnoff (*av)++; (*ac)--; 610ead75a59SLuigi Rizzo 611ead75a59SLuigi Rizzo /* 612ead75a59SLuigi Rizzo * Extract optional remote address. 613ead75a59SLuigi Rizzo */ 614ead75a59SLuigi Rizzo /* see above in setup_redir_port() */ 615ce972082SGleb Smirnoff if (*ac != 0 && isdigit(***av)) { 616d5a80549SGleb Smirnoff StrToAddr(**av, &r->raddr); 617d5a80549SGleb Smirnoff (*av)++; (*ac)--; 618ead75a59SLuigi Rizzo } 619ead75a59SLuigi Rizzo } 620ead75a59SLuigi Rizzo } 621d5a80549SGleb Smirnoff 622ead75a59SLuigi Rizzo return (space); 623ead75a59SLuigi Rizzo } 624ead75a59SLuigi Rizzo 625ead75a59SLuigi Rizzo static void 62656707beeSMark Johnston nat_show_log(struct nat44_cfg_nat *n, void *arg __unused) 627ead75a59SLuigi Rizzo { 628d6164b77SAlexander V. Chernikov char *buf; 629d6164b77SAlexander V. Chernikov 630d6164b77SAlexander V. Chernikov buf = (char *)(n + 1); 631d6164b77SAlexander V. Chernikov if (buf[0] != '\0') 632d6164b77SAlexander V. Chernikov printf("nat %s: %s\n", n->name, buf); 633d6164b77SAlexander V. Chernikov } 634d6164b77SAlexander V. Chernikov 635d6164b77SAlexander V. Chernikov static void 63656707beeSMark Johnston nat_show_cfg(struct nat44_cfg_nat *n, void *arg __unused) 637d6164b77SAlexander V. Chernikov { 638d6164b77SAlexander V. Chernikov struct nat44_cfg_redir *t; 639d6164b77SAlexander V. Chernikov struct nat44_cfg_spool *s; 640d6164b77SAlexander V. Chernikov caddr_t buf; 641ead75a59SLuigi Rizzo struct protoent *p; 64256707beeSMark Johnston uint32_t cnt; 64356707beeSMark Johnston int i, off; 644ead75a59SLuigi Rizzo 645d6164b77SAlexander V. Chernikov buf = (caddr_t)n; 646ead75a59SLuigi Rizzo off = sizeof(*n); 647d6164b77SAlexander V. Chernikov printf("ipfw nat %s config", n->name); 648ead75a59SLuigi Rizzo if (strlen(n->if_name) != 0) 649ead75a59SLuigi Rizzo printf(" if %s", n->if_name); 650ead75a59SLuigi Rizzo else if (n->ip.s_addr != 0) 651ead75a59SLuigi Rizzo printf(" ip %s", inet_ntoa(n->ip)); 652ead75a59SLuigi Rizzo while (n->mode != 0) { 653ead75a59SLuigi Rizzo if (n->mode & PKT_ALIAS_LOG) { 654ead75a59SLuigi Rizzo printf(" log"); 655ead75a59SLuigi Rizzo n->mode &= ~PKT_ALIAS_LOG; 656ead75a59SLuigi Rizzo } else if (n->mode & PKT_ALIAS_DENY_INCOMING) { 657ead75a59SLuigi Rizzo printf(" deny_in"); 658ead75a59SLuigi Rizzo n->mode &= ~PKT_ALIAS_DENY_INCOMING; 659ead75a59SLuigi Rizzo } else if (n->mode & PKT_ALIAS_SAME_PORTS) { 660ead75a59SLuigi Rizzo printf(" same_ports"); 661ead75a59SLuigi Rizzo n->mode &= ~PKT_ALIAS_SAME_PORTS; 6621875bbfeSAndrey V. Elsukov } else if (n->mode & PKT_ALIAS_SKIP_GLOBAL) { 6631875bbfeSAndrey V. Elsukov printf(" skip_global"); 6641875bbfeSAndrey V. Elsukov n->mode &= ~PKT_ALIAS_SKIP_GLOBAL; 665ead75a59SLuigi Rizzo } else if (n->mode & PKT_ALIAS_UNREGISTERED_ONLY) { 666ead75a59SLuigi Rizzo printf(" unreg_only"); 667ead75a59SLuigi Rizzo n->mode &= ~PKT_ALIAS_UNREGISTERED_ONLY; 66875b89337SAlexander V. Chernikov } else if (n->mode & PKT_ALIAS_UNREGISTERED_CGN) { 66975b89337SAlexander V. Chernikov printf(" unreg_cgn"); 67075b89337SAlexander V. Chernikov n->mode &= ~PKT_ALIAS_UNREGISTERED_CGN; 671ead75a59SLuigi Rizzo } else if (n->mode & PKT_ALIAS_RESET_ON_ADDR_CHANGE) { 672ead75a59SLuigi Rizzo printf(" reset"); 673ead75a59SLuigi Rizzo n->mode &= ~PKT_ALIAS_RESET_ON_ADDR_CHANGE; 674ead75a59SLuigi Rizzo } else if (n->mode & PKT_ALIAS_REVERSE) { 675ead75a59SLuigi Rizzo printf(" reverse"); 676ead75a59SLuigi Rizzo n->mode &= ~PKT_ALIAS_REVERSE; 677ead75a59SLuigi Rizzo } else if (n->mode & PKT_ALIAS_PROXY_ONLY) { 678ead75a59SLuigi Rizzo printf(" proxy_only"); 679ead75a59SLuigi Rizzo n->mode &= ~PKT_ALIAS_PROXY_ONLY; 680*b6c90b90SDamjan Jovanovic } else if (n->mode & PKT_ALIAS_UDP_EIM) { 681*b6c90b90SDamjan Jovanovic printf(" udp_eim"); 682*b6c90b90SDamjan Jovanovic n->mode &= ~PKT_ALIAS_UDP_EIM; 683ead75a59SLuigi Rizzo } 684ead75a59SLuigi Rizzo } 685ead75a59SLuigi Rizzo /* Print all the redirect's data configuration. */ 686ead75a59SLuigi Rizzo for (cnt = 0; cnt < n->redir_cnt; cnt++) { 687d6164b77SAlexander V. Chernikov t = (struct nat44_cfg_redir *)&buf[off]; 688d6164b77SAlexander V. Chernikov off += sizeof(struct nat44_cfg_redir); 689ead75a59SLuigi Rizzo switch (t->mode) { 690ead75a59SLuigi Rizzo case REDIR_ADDR: 691ead75a59SLuigi Rizzo printf(" redirect_addr"); 692ead75a59SLuigi Rizzo if (t->spool_cnt == 0) 693ead75a59SLuigi Rizzo printf(" %s", inet_ntoa(t->laddr)); 694ead75a59SLuigi Rizzo else 695ead75a59SLuigi Rizzo for (i = 0; i < t->spool_cnt; i++) { 696d6164b77SAlexander V. Chernikov s = (struct nat44_cfg_spool *)&buf[off]; 697ead75a59SLuigi Rizzo if (i) 698ead75a59SLuigi Rizzo printf(","); 699ead75a59SLuigi Rizzo else 700ead75a59SLuigi Rizzo printf(" "); 701ead75a59SLuigi Rizzo printf("%s", inet_ntoa(s->addr)); 702d6164b77SAlexander V. Chernikov off += sizeof(struct nat44_cfg_spool); 703ead75a59SLuigi Rizzo } 704ead75a59SLuigi Rizzo printf(" %s", inet_ntoa(t->paddr)); 705ead75a59SLuigi Rizzo break; 706ead75a59SLuigi Rizzo case REDIR_PORT: 707ead75a59SLuigi Rizzo p = getprotobynumber(t->proto); 708ead75a59SLuigi Rizzo printf(" redirect_port %s ", p->p_name); 709ead75a59SLuigi Rizzo if (!t->spool_cnt) { 710ead75a59SLuigi Rizzo printf("%s:%u", inet_ntoa(t->laddr), t->lport); 711ead75a59SLuigi Rizzo if (t->pport_cnt > 1) 712ead75a59SLuigi Rizzo printf("-%u", t->lport + 713ead75a59SLuigi Rizzo t->pport_cnt - 1); 714ead75a59SLuigi Rizzo } else 715ead75a59SLuigi Rizzo for (i=0; i < t->spool_cnt; i++) { 716d6164b77SAlexander V. Chernikov s = (struct nat44_cfg_spool *)&buf[off]; 717ead75a59SLuigi Rizzo if (i) 718ead75a59SLuigi Rizzo printf(","); 719ead75a59SLuigi Rizzo printf("%s:%u", inet_ntoa(s->addr), 720ead75a59SLuigi Rizzo s->port); 721d6164b77SAlexander V. Chernikov off += sizeof(struct nat44_cfg_spool); 722ead75a59SLuigi Rizzo } 723ead75a59SLuigi Rizzo 724ead75a59SLuigi Rizzo printf(" "); 725ead75a59SLuigi Rizzo if (t->paddr.s_addr) 726ead75a59SLuigi Rizzo printf("%s:", inet_ntoa(t->paddr)); 727ead75a59SLuigi Rizzo printf("%u", t->pport); 728ead75a59SLuigi Rizzo if (!t->spool_cnt && t->pport_cnt > 1) 729ead75a59SLuigi Rizzo printf("-%u", t->pport + t->pport_cnt - 1); 730ead75a59SLuigi Rizzo 731ead75a59SLuigi Rizzo if (t->raddr.s_addr) { 732ead75a59SLuigi Rizzo printf(" %s", inet_ntoa(t->raddr)); 733ead75a59SLuigi Rizzo if (t->rport) { 734ead75a59SLuigi Rizzo printf(":%u", t->rport); 735ead75a59SLuigi Rizzo if (!t->spool_cnt && t->rport_cnt > 1) 736ead75a59SLuigi Rizzo printf("-%u", t->rport + 737ead75a59SLuigi Rizzo t->rport_cnt - 1); 738ead75a59SLuigi Rizzo } 739ead75a59SLuigi Rizzo } 740ead75a59SLuigi Rizzo break; 741ead75a59SLuigi Rizzo case REDIR_PROTO: 742ead75a59SLuigi Rizzo p = getprotobynumber(t->proto); 743ead75a59SLuigi Rizzo printf(" redirect_proto %s %s", p->p_name, 744ead75a59SLuigi Rizzo inet_ntoa(t->laddr)); 745ead75a59SLuigi Rizzo if (t->paddr.s_addr != 0) { 746ead75a59SLuigi Rizzo printf(" %s", inet_ntoa(t->paddr)); 747ead75a59SLuigi Rizzo if (t->raddr.s_addr) 748ead75a59SLuigi Rizzo printf(" %s", inet_ntoa(t->raddr)); 749ead75a59SLuigi Rizzo } 750ead75a59SLuigi Rizzo break; 751ead75a59SLuigi Rizzo default: 752ead75a59SLuigi Rizzo errx(EX_DATAERR, "unknown redir mode"); 753ead75a59SLuigi Rizzo break; 754ead75a59SLuigi Rizzo } 755ead75a59SLuigi Rizzo } 756ead75a59SLuigi Rizzo printf("\n"); 757ead75a59SLuigi Rizzo } 758ead75a59SLuigi Rizzo 759a08cdb6cSNeel Chauhan static int 760a08cdb6cSNeel Chauhan nat_port_alias_parse(char *str, u_short *lpout, u_short *hpout) { 761a08cdb6cSNeel Chauhan long lp, hp; 762a08cdb6cSNeel Chauhan char *ptr; 763a08cdb6cSNeel Chauhan /* Lower port parsing */ 764a08cdb6cSNeel Chauhan lp = (long) strtol(str, &ptr, 10); 765a08cdb6cSNeel Chauhan if (lp < 1024 || lp > 65535) 766a08cdb6cSNeel Chauhan return 0; 767a08cdb6cSNeel Chauhan if (!ptr || *ptr != '-') 768a08cdb6cSNeel Chauhan return 0; 769a08cdb6cSNeel Chauhan /* Upper port parsing */ 770a08cdb6cSNeel Chauhan hp = (long) strtol(ptr, &ptr, 10); 771a08cdb6cSNeel Chauhan if (hp < 1024 || hp > 65535) 772a08cdb6cSNeel Chauhan return 0; 773a08cdb6cSNeel Chauhan if (ptr) 774a08cdb6cSNeel Chauhan return 0; 775a08cdb6cSNeel Chauhan 776a08cdb6cSNeel Chauhan *lpout = (u_short) lp; 777a08cdb6cSNeel Chauhan *hpout = (u_short) hp; 778a08cdb6cSNeel Chauhan return 1; 779a08cdb6cSNeel Chauhan } 780a08cdb6cSNeel Chauhan 781ead75a59SLuigi Rizzo void 782ead75a59SLuigi Rizzo ipfw_config_nat(int ac, char **av) 783ead75a59SLuigi Rizzo { 784d6164b77SAlexander V. Chernikov ipfw_obj_header *oh; 785d6164b77SAlexander V. Chernikov struct nat44_cfg_nat *n; /* Nat instance configuration. */ 786d5a80549SGleb Smirnoff int i, off, tok, ac1; 787a08cdb6cSNeel Chauhan u_short lp, hp; 788980cccebSAndrey V. Elsukov char *id, *buf, **av1, *end; 789d5a80549SGleb Smirnoff size_t len; 790ead75a59SLuigi Rizzo 7916ca60bebSGleb Smirnoff av++; 7926ca60bebSGleb Smirnoff ac--; 793ead75a59SLuigi Rizzo /* Nat id. */ 794980cccebSAndrey V. Elsukov if (ac == 0) 795ead75a59SLuigi Rizzo errx(EX_DATAERR, "missing nat id"); 796980cccebSAndrey V. Elsukov id = *av; 797980cccebSAndrey V. Elsukov i = (int)strtol(id, &end, 0); 798980cccebSAndrey V. Elsukov if (i <= 0 || *end != '\0') 799980cccebSAndrey V. Elsukov errx(EX_DATAERR, "illegal nat id: %s", id); 8006ca60bebSGleb Smirnoff av++; 8016ca60bebSGleb Smirnoff ac--; 802ead75a59SLuigi Rizzo if (ac == 0) 803ead75a59SLuigi Rizzo errx(EX_DATAERR, "missing option"); 804ead75a59SLuigi Rizzo 805d6164b77SAlexander V. Chernikov len = sizeof(*oh) + sizeof(*n); 806d5a80549SGleb Smirnoff ac1 = ac; 807d5a80549SGleb Smirnoff av1 = av; 808d5a80549SGleb Smirnoff while (ac1 > 0) { 809d5a80549SGleb Smirnoff tok = match_token(nat_params, *av1); 8106ca60bebSGleb Smirnoff ac1--; 8116ca60bebSGleb Smirnoff av1++; 812d5a80549SGleb Smirnoff switch (tok) { 813d5a80549SGleb Smirnoff case TOK_IP: 814d5a80549SGleb Smirnoff case TOK_IF: 815a08cdb6cSNeel Chauhan case TOK_PORT_ALIAS: 8166ca60bebSGleb Smirnoff ac1--; 8176ca60bebSGleb Smirnoff av1++; 818d5a80549SGleb Smirnoff break; 819d5a80549SGleb Smirnoff case TOK_ALOG: 820d5a80549SGleb Smirnoff case TOK_DENY_INC: 821d5a80549SGleb Smirnoff case TOK_SAME_PORTS: 8221875bbfeSAndrey V. Elsukov case TOK_SKIP_GLOBAL: 823d5a80549SGleb Smirnoff case TOK_UNREG_ONLY: 82404777538SEugene Grosbein case TOK_UNREG_CGN: 825d5a80549SGleb Smirnoff case TOK_RESET_ADDR: 826d5a80549SGleb Smirnoff case TOK_ALIAS_REV: 827d5a80549SGleb Smirnoff case TOK_PROXY_ONLY: 828*b6c90b90SDamjan Jovanovic case TOK_UDP_EIM: 829d5a80549SGleb Smirnoff break; 830d5a80549SGleb Smirnoff case TOK_REDIR_ADDR: 831d5a80549SGleb Smirnoff if (ac1 < 2) 832d5a80549SGleb Smirnoff errx(EX_DATAERR, "redirect_addr: " 833d5a80549SGleb Smirnoff "not enough arguments"); 834d5a80549SGleb Smirnoff len += estimate_redir_addr(&ac1, &av1); 8356ca60bebSGleb Smirnoff av1 += 2; 8366ca60bebSGleb Smirnoff ac1 -= 2; 837d5a80549SGleb Smirnoff break; 838d5a80549SGleb Smirnoff case TOK_REDIR_PORT: 839d5a80549SGleb Smirnoff if (ac1 < 3) 840d5a80549SGleb Smirnoff errx(EX_DATAERR, "redirect_port: " 841d5a80549SGleb Smirnoff "not enough arguments"); 8426ca60bebSGleb Smirnoff av1++; 8436ca60bebSGleb Smirnoff ac1--; 844d5a80549SGleb Smirnoff len += estimate_redir_port(&ac1, &av1); 8456ca60bebSGleb Smirnoff av1 += 2; 8466ca60bebSGleb Smirnoff ac1 -= 2; 847ce972082SGleb Smirnoff /* Skip optional remoteIP/port */ 8480103912dSGleb Smirnoff if (ac1 != 0 && isdigit(**av1)) { 8496ca60bebSGleb Smirnoff av1++; 8506ca60bebSGleb Smirnoff ac1--; 8510103912dSGleb Smirnoff } 852d5a80549SGleb Smirnoff break; 853d5a80549SGleb Smirnoff case TOK_REDIR_PROTO: 854d5a80549SGleb Smirnoff if (ac1 < 2) 855d5a80549SGleb Smirnoff errx(EX_DATAERR, "redirect_proto: " 856d5a80549SGleb Smirnoff "not enough arguments"); 857d6164b77SAlexander V. Chernikov len += sizeof(struct nat44_cfg_redir); 8586ca60bebSGleb Smirnoff av1 += 2; 8596ca60bebSGleb Smirnoff ac1 -= 2; 860ce972082SGleb Smirnoff /* Skip optional remoteIP/port */ 8610103912dSGleb Smirnoff if (ac1 != 0 && isdigit(**av1)) { 8626ca60bebSGleb Smirnoff av1++; 8636ca60bebSGleb Smirnoff ac1--; 8640103912dSGleb Smirnoff } 8650103912dSGleb Smirnoff if (ac1 != 0 && isdigit(**av1)) { 8666ca60bebSGleb Smirnoff av1++; 8676ca60bebSGleb Smirnoff ac1--; 8680103912dSGleb Smirnoff } 869d5a80549SGleb Smirnoff break; 870d5a80549SGleb Smirnoff default: 871d5a80549SGleb Smirnoff errx(EX_DATAERR, "unrecognised option ``%s''", av1[-1]); 872d5a80549SGleb Smirnoff } 873d5a80549SGleb Smirnoff } 874d5a80549SGleb Smirnoff 875d5a80549SGleb Smirnoff if ((buf = malloc(len)) == NULL) 876d5a80549SGleb Smirnoff errx(EX_OSERR, "malloc failed"); 877d5a80549SGleb Smirnoff 878d6164b77SAlexander V. Chernikov /* Offset in buf: save space for header at the beginning. */ 879d6164b77SAlexander V. Chernikov off = sizeof(*oh) + sizeof(*n); 880d5a80549SGleb Smirnoff memset(buf, 0, len); 881d6164b77SAlexander V. Chernikov oh = (ipfw_obj_header *)buf; 882d6164b77SAlexander V. Chernikov n = (struct nat44_cfg_nat *)(oh + 1); 883d6164b77SAlexander V. Chernikov oh->ntlv.head.length = sizeof(oh->ntlv); 884d6164b77SAlexander V. Chernikov snprintf(oh->ntlv.name, sizeof(oh->ntlv.name), "%d", i); 885d6164b77SAlexander V. Chernikov snprintf(n->name, sizeof(n->name), "%d", i); 886d5a80549SGleb Smirnoff 887ead75a59SLuigi Rizzo while (ac > 0) { 888ead75a59SLuigi Rizzo tok = match_token(nat_params, *av); 8896ca60bebSGleb Smirnoff ac--; 8906ca60bebSGleb Smirnoff av++; 891ead75a59SLuigi Rizzo switch (tok) { 892ead75a59SLuigi Rizzo case TOK_IP: 893ead75a59SLuigi Rizzo if (ac == 0) 894ead75a59SLuigi Rizzo errx(EX_DATAERR, "missing option"); 895ead75a59SLuigi Rizzo if (!inet_aton(av[0], &(n->ip))) 896ead75a59SLuigi Rizzo errx(EX_DATAERR, "bad ip address ``%s''", 897ead75a59SLuigi Rizzo av[0]); 8986ca60bebSGleb Smirnoff ac--; 8996ca60bebSGleb Smirnoff av++; 900ead75a59SLuigi Rizzo break; 901ead75a59SLuigi Rizzo case TOK_IF: 902ead75a59SLuigi Rizzo if (ac == 0) 903ead75a59SLuigi Rizzo errx(EX_DATAERR, "missing option"); 904ead75a59SLuigi Rizzo set_addr_dynamic(av[0], n); 9056ca60bebSGleb Smirnoff ac--; 9066ca60bebSGleb Smirnoff av++; 907ead75a59SLuigi Rizzo break; 908ead75a59SLuigi Rizzo case TOK_ALOG: 909ead75a59SLuigi Rizzo n->mode |= PKT_ALIAS_LOG; 910ead75a59SLuigi Rizzo break; 911ead75a59SLuigi Rizzo case TOK_DENY_INC: 912ead75a59SLuigi Rizzo n->mode |= PKT_ALIAS_DENY_INCOMING; 913ead75a59SLuigi Rizzo break; 914ead75a59SLuigi Rizzo case TOK_SAME_PORTS: 915ead75a59SLuigi Rizzo n->mode |= PKT_ALIAS_SAME_PORTS; 916ead75a59SLuigi Rizzo break; 917ead75a59SLuigi Rizzo case TOK_UNREG_ONLY: 918ead75a59SLuigi Rizzo n->mode |= PKT_ALIAS_UNREGISTERED_ONLY; 919ead75a59SLuigi Rizzo break; 92004777538SEugene Grosbein case TOK_UNREG_CGN: 92104777538SEugene Grosbein n->mode |= PKT_ALIAS_UNREGISTERED_CGN; 92204777538SEugene Grosbein break; 9231875bbfeSAndrey V. Elsukov case TOK_SKIP_GLOBAL: 9241875bbfeSAndrey V. Elsukov n->mode |= PKT_ALIAS_SKIP_GLOBAL; 9251875bbfeSAndrey V. Elsukov break; 926ead75a59SLuigi Rizzo case TOK_RESET_ADDR: 927ead75a59SLuigi Rizzo n->mode |= PKT_ALIAS_RESET_ON_ADDR_CHANGE; 928ead75a59SLuigi Rizzo break; 929ead75a59SLuigi Rizzo case TOK_ALIAS_REV: 930ead75a59SLuigi Rizzo n->mode |= PKT_ALIAS_REVERSE; 931ead75a59SLuigi Rizzo break; 932ead75a59SLuigi Rizzo case TOK_PROXY_ONLY: 933ead75a59SLuigi Rizzo n->mode |= PKT_ALIAS_PROXY_ONLY; 934ead75a59SLuigi Rizzo break; 935*b6c90b90SDamjan Jovanovic case TOK_UDP_EIM: 936*b6c90b90SDamjan Jovanovic n->mode |= PKT_ALIAS_UDP_EIM; 937*b6c90b90SDamjan Jovanovic break; 938ead75a59SLuigi Rizzo /* 9395221106cSGleb Smirnoff * All the setup_redir_* functions work directly in 9405221106cSGleb Smirnoff * the final buffer, see above for details. 941ead75a59SLuigi Rizzo */ 942ead75a59SLuigi Rizzo case TOK_REDIR_ADDR: 943ead75a59SLuigi Rizzo case TOK_REDIR_PORT: 944ead75a59SLuigi Rizzo case TOK_REDIR_PROTO: 945ead75a59SLuigi Rizzo switch (tok) { 946ead75a59SLuigi Rizzo case TOK_REDIR_ADDR: 947d5a80549SGleb Smirnoff i = setup_redir_addr(&buf[off], &ac, &av); 948ead75a59SLuigi Rizzo break; 949ead75a59SLuigi Rizzo case TOK_REDIR_PORT: 950d5a80549SGleb Smirnoff i = setup_redir_port(&buf[off], &ac, &av); 951ead75a59SLuigi Rizzo break; 952ead75a59SLuigi Rizzo case TOK_REDIR_PROTO: 953d5a80549SGleb Smirnoff i = setup_redir_proto(&buf[off], &ac, &av); 954ead75a59SLuigi Rizzo break; 955ead75a59SLuigi Rizzo } 956ead75a59SLuigi Rizzo n->redir_cnt++; 957ead75a59SLuigi Rizzo off += i; 958ead75a59SLuigi Rizzo break; 959a08cdb6cSNeel Chauhan case TOK_PORT_ALIAS: 960a08cdb6cSNeel Chauhan if (ac == 0) 961a08cdb6cSNeel Chauhan errx(EX_DATAERR, "missing option"); 962a08cdb6cSNeel Chauhan if (!nat_port_alias_parse(av[0], &lp, &hp)) 963a08cdb6cSNeel Chauhan errx(EX_DATAERR, 964a08cdb6cSNeel Chauhan "You need a range of port(s) from 1024 <= x < 65536"); 965a08cdb6cSNeel Chauhan if (lp >= hp) 966a08cdb6cSNeel Chauhan errx(EX_DATAERR, 967a08cdb6cSNeel Chauhan "Upper port has to be greater than lower port"); 968a08cdb6cSNeel Chauhan n->alias_port_lo = lp; 969a08cdb6cSNeel Chauhan n->alias_port_hi = hp; 970a08cdb6cSNeel Chauhan ac--; 971a08cdb6cSNeel Chauhan av++; 972a08cdb6cSNeel Chauhan break; 973ead75a59SLuigi Rizzo } 974ead75a59SLuigi Rizzo } 975a08cdb6cSNeel Chauhan if (n->mode & PKT_ALIAS_SAME_PORTS && n->alias_port_lo) 976a08cdb6cSNeel Chauhan errx(EX_DATAERR, "same_ports and port_range cannot both be selected"); 977ead75a59SLuigi Rizzo 978d6164b77SAlexander V. Chernikov i = do_set3(IP_FW_NAT44_XCONFIG, &oh->opheader, len); 979d6164b77SAlexander V. Chernikov if (i != 0) 980d6164b77SAlexander V. Chernikov err(1, "setsockopt(%s)", "IP_FW_NAT44_XCONFIG"); 981ead75a59SLuigi Rizzo 98256707beeSMark Johnston if (!g_co.do_quiet) { 983ead75a59SLuigi Rizzo /* After every modification, we show the resultant rule. */ 984ead75a59SLuigi Rizzo int _ac = 3; 985d7a32e24SLuigi Rizzo const char *_av[] = {"show", "config", id}; 986d7a32e24SLuigi Rizzo ipfw_show_nat(_ac, (char **)(void *)_av); 987ead75a59SLuigi Rizzo } 988ead75a59SLuigi Rizzo } 989ead75a59SLuigi Rizzo 990db1102f2SAndrey V. Elsukov static void 991db1102f2SAndrey V. Elsukov nat_fill_ntlv(ipfw_obj_ntlv *ntlv, int i) 992db1102f2SAndrey V. Elsukov { 993db1102f2SAndrey V. Elsukov 994db1102f2SAndrey V. Elsukov ntlv->head.type = IPFW_TLV_EACTION_NAME(1); /* it doesn't matter */ 995db1102f2SAndrey V. Elsukov ntlv->head.length = sizeof(ipfw_obj_ntlv); 996db1102f2SAndrey V. Elsukov ntlv->idx = 1; 997db1102f2SAndrey V. Elsukov ntlv->set = 0; /* not yet */ 998db1102f2SAndrey V. Elsukov snprintf(ntlv->name, sizeof(ntlv->name), "%d", i); 999db1102f2SAndrey V. Elsukov } 1000db1102f2SAndrey V. Elsukov 1001db1102f2SAndrey V. Elsukov int 1002db1102f2SAndrey V. Elsukov ipfw_delete_nat(int i) 1003db1102f2SAndrey V. Elsukov { 1004db1102f2SAndrey V. Elsukov ipfw_obj_header oh; 1005db1102f2SAndrey V. Elsukov int ret; 1006db1102f2SAndrey V. Elsukov 1007db1102f2SAndrey V. Elsukov memset(&oh, 0, sizeof(oh)); 1008db1102f2SAndrey V. Elsukov nat_fill_ntlv(&oh.ntlv, i); 1009db1102f2SAndrey V. Elsukov ret = do_set3(IP_FW_NAT44_DESTROY, &oh.opheader, sizeof(oh)); 1010db1102f2SAndrey V. Elsukov if (ret == -1) { 101156707beeSMark Johnston if (!g_co.do_quiet) 1012db1102f2SAndrey V. Elsukov warn("nat %u not available", i); 1013db1102f2SAndrey V. Elsukov return (EX_UNAVAILABLE); 1014db1102f2SAndrey V. Elsukov } 1015db1102f2SAndrey V. Elsukov return (EX_OK); 1016db1102f2SAndrey V. Elsukov } 1017db1102f2SAndrey V. Elsukov 1018d6164b77SAlexander V. Chernikov struct nat_list_arg { 1019d6164b77SAlexander V. Chernikov uint16_t cmd; 1020d6164b77SAlexander V. Chernikov int is_all; 1021d6164b77SAlexander V. Chernikov }; 1022d6164b77SAlexander V. Chernikov 1023d6164b77SAlexander V. Chernikov static int 1024d6164b77SAlexander V. Chernikov nat_show_data(struct nat44_cfg_nat *cfg, void *arg) 1025d6164b77SAlexander V. Chernikov { 1026d6164b77SAlexander V. Chernikov struct nat_list_arg *nla; 1027d6164b77SAlexander V. Chernikov ipfw_obj_header *oh; 1028d6164b77SAlexander V. Chernikov 1029d6164b77SAlexander V. Chernikov nla = (struct nat_list_arg *)arg; 1030d6164b77SAlexander V. Chernikov 1031d6164b77SAlexander V. Chernikov switch (nla->cmd) { 1032d6164b77SAlexander V. Chernikov case IP_FW_NAT44_XGETCONFIG: 1033d6164b77SAlexander V. Chernikov if (nat_get_cmd(cfg->name, nla->cmd, &oh) != 0) { 1034d6164b77SAlexander V. Chernikov warnx("Error getting nat instance %s info", cfg->name); 1035d6164b77SAlexander V. Chernikov break; 1036d6164b77SAlexander V. Chernikov } 1037d6164b77SAlexander V. Chernikov nat_show_cfg((struct nat44_cfg_nat *)(oh + 1), NULL); 1038d6164b77SAlexander V. Chernikov free(oh); 1039d6164b77SAlexander V. Chernikov break; 1040d6164b77SAlexander V. Chernikov case IP_FW_NAT44_XGETLOG: 1041d6164b77SAlexander V. Chernikov if (nat_get_cmd(cfg->name, nla->cmd, &oh) == 0) { 1042d6164b77SAlexander V. Chernikov nat_show_log((struct nat44_cfg_nat *)(oh + 1), NULL); 1043d6164b77SAlexander V. Chernikov free(oh); 1044d6164b77SAlexander V. Chernikov break; 1045d6164b77SAlexander V. Chernikov } 1046d6164b77SAlexander V. Chernikov /* Handle error */ 1047d6164b77SAlexander V. Chernikov if (nla->is_all != 0 && errno == ENOENT) 1048d6164b77SAlexander V. Chernikov break; 1049d6164b77SAlexander V. Chernikov warn("Error getting nat instance %s info", cfg->name); 1050d6164b77SAlexander V. Chernikov break; 1051d6164b77SAlexander V. Chernikov } 1052d6164b77SAlexander V. Chernikov 1053d6164b77SAlexander V. Chernikov return (0); 1054d6164b77SAlexander V. Chernikov } 1055d6164b77SAlexander V. Chernikov 1056d6164b77SAlexander V. Chernikov /* 1057d6164b77SAlexander V. Chernikov * Compare nat names. 1058d6164b77SAlexander V. Chernikov * Honor number comparison. 1059d6164b77SAlexander V. Chernikov */ 1060d6164b77SAlexander V. Chernikov static int 1061d6164b77SAlexander V. Chernikov natname_cmp(const void *a, const void *b) 1062d6164b77SAlexander V. Chernikov { 106356707beeSMark Johnston const struct nat44_cfg_nat *ia, *ib; 1064d6164b77SAlexander V. Chernikov 106556707beeSMark Johnston ia = (const struct nat44_cfg_nat *)a; 106656707beeSMark Johnston ib = (const struct nat44_cfg_nat *)b; 1067d6164b77SAlexander V. Chernikov 1068d6164b77SAlexander V. Chernikov return (stringnum_cmp(ia->name, ib->name)); 1069d6164b77SAlexander V. Chernikov } 1070d6164b77SAlexander V. Chernikov 1071d6164b77SAlexander V. Chernikov /* 1072d6164b77SAlexander V. Chernikov * Retrieves nat list from kernel, 1073d6164b77SAlexander V. Chernikov * optionally sorts it and calls requested function for each table. 1074d6164b77SAlexander V. Chernikov * Returns 0 on success. 1075d6164b77SAlexander V. Chernikov */ 1076d6164b77SAlexander V. Chernikov static int 1077d6164b77SAlexander V. Chernikov nat_foreach(nat_cb_t *f, void *arg, int sort) 1078d6164b77SAlexander V. Chernikov { 1079d6164b77SAlexander V. Chernikov ipfw_obj_lheader *olh; 1080d6164b77SAlexander V. Chernikov struct nat44_cfg_nat *cfg; 1081d6164b77SAlexander V. Chernikov size_t sz; 108256707beeSMark Johnston uint32_t i; 1083d6164b77SAlexander V. Chernikov 1084d6164b77SAlexander V. Chernikov /* Start with reasonable default */ 1085d6164b77SAlexander V. Chernikov sz = sizeof(*olh) + 16 * sizeof(struct nat44_cfg_nat); 1086d6164b77SAlexander V. Chernikov 1087d6164b77SAlexander V. Chernikov for (;;) { 1088d6164b77SAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 1089d6164b77SAlexander V. Chernikov return (ENOMEM); 1090d6164b77SAlexander V. Chernikov 1091d6164b77SAlexander V. Chernikov olh->size = sz; 1092d6164b77SAlexander V. Chernikov if (do_get3(IP_FW_NAT44_LIST_NAT, &olh->opheader, &sz) != 0) { 1093d6164b77SAlexander V. Chernikov sz = olh->size; 10940577d6e0SAlexander V. Chernikov free(olh); 10950577d6e0SAlexander V. Chernikov if (errno == ENOMEM) 1096d6164b77SAlexander V. Chernikov continue; 1097d6164b77SAlexander V. Chernikov return (errno); 1098d6164b77SAlexander V. Chernikov } 1099d6164b77SAlexander V. Chernikov 1100d6164b77SAlexander V. Chernikov if (sort != 0) 1101d6164b77SAlexander V. Chernikov qsort(olh + 1, olh->count, olh->objsize, natname_cmp); 1102d6164b77SAlexander V. Chernikov 1103d6164b77SAlexander V. Chernikov cfg = (struct nat44_cfg_nat*)(olh + 1); 1104d6164b77SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 1105f5e73306SJohn Baldwin (void)f(cfg, arg); /* Ignore errors for now */ 1106d6164b77SAlexander V. Chernikov cfg = (struct nat44_cfg_nat *)((caddr_t)cfg + 1107d6164b77SAlexander V. Chernikov olh->objsize); 1108d6164b77SAlexander V. Chernikov } 1109d6164b77SAlexander V. Chernikov 1110d6164b77SAlexander V. Chernikov free(olh); 1111d6164b77SAlexander V. Chernikov break; 1112d6164b77SAlexander V. Chernikov } 1113d6164b77SAlexander V. Chernikov 1114d6164b77SAlexander V. Chernikov return (0); 1115d6164b77SAlexander V. Chernikov } 1116d6164b77SAlexander V. Chernikov 1117d6164b77SAlexander V. Chernikov static int 1118d6164b77SAlexander V. Chernikov nat_get_cmd(char *name, uint16_t cmd, ipfw_obj_header **ooh) 1119d6164b77SAlexander V. Chernikov { 1120d6164b77SAlexander V. Chernikov ipfw_obj_header *oh; 1121d6164b77SAlexander V. Chernikov struct nat44_cfg_nat *cfg; 1122d6164b77SAlexander V. Chernikov size_t sz; 1123d6164b77SAlexander V. Chernikov 1124d6164b77SAlexander V. Chernikov /* Start with reasonable default */ 1125d6164b77SAlexander V. Chernikov sz = sizeof(*oh) + sizeof(*cfg) + 128; 1126d6164b77SAlexander V. Chernikov 1127d6164b77SAlexander V. Chernikov for (;;) { 1128d6164b77SAlexander V. Chernikov if ((oh = calloc(1, sz)) == NULL) 1129d6164b77SAlexander V. Chernikov return (ENOMEM); 1130d6164b77SAlexander V. Chernikov cfg = (struct nat44_cfg_nat *)(oh + 1); 1131d6164b77SAlexander V. Chernikov oh->ntlv.head.length = sizeof(oh->ntlv); 1132d6164b77SAlexander V. Chernikov strlcpy(oh->ntlv.name, name, sizeof(oh->ntlv.name)); 1133d6164b77SAlexander V. Chernikov strlcpy(cfg->name, name, sizeof(cfg->name)); 1134d6164b77SAlexander V. Chernikov 1135d6164b77SAlexander V. Chernikov if (do_get3(cmd, &oh->opheader, &sz) != 0) { 1136d6164b77SAlexander V. Chernikov sz = cfg->size; 1137d6164b77SAlexander V. Chernikov free(oh); 1138d6164b77SAlexander V. Chernikov if (errno == ENOMEM) 1139d6164b77SAlexander V. Chernikov continue; 1140d6164b77SAlexander V. Chernikov return (errno); 1141d6164b77SAlexander V. Chernikov } 1142d6164b77SAlexander V. Chernikov 1143d6164b77SAlexander V. Chernikov *ooh = oh; 1144d6164b77SAlexander V. Chernikov break; 1145d6164b77SAlexander V. Chernikov } 1146d6164b77SAlexander V. Chernikov 1147d6164b77SAlexander V. Chernikov return (0); 1148d6164b77SAlexander V. Chernikov } 1149ead75a59SLuigi Rizzo 1150ead75a59SLuigi Rizzo void 1151ead75a59SLuigi Rizzo ipfw_show_nat(int ac, char **av) 1152ead75a59SLuigi Rizzo { 1153d6164b77SAlexander V. Chernikov ipfw_obj_header *oh; 1154d6164b77SAlexander V. Chernikov char *name; 1155d6164b77SAlexander V. Chernikov int cmd; 1156d6164b77SAlexander V. Chernikov struct nat_list_arg nla; 1157ead75a59SLuigi Rizzo 11586ca60bebSGleb Smirnoff ac--; 11596ca60bebSGleb Smirnoff av++; 1160ead75a59SLuigi Rizzo 116156707beeSMark Johnston if (g_co.test_only) 1162ead75a59SLuigi Rizzo return; 1163ead75a59SLuigi Rizzo 1164ead75a59SLuigi Rizzo /* Parse parameters. */ 1165d6164b77SAlexander V. Chernikov cmd = 0; /* XXX: Change to IP_FW_NAT44_XGETLOG @ MFC */ 1166d6164b77SAlexander V. Chernikov name = NULL; 1167d6164b77SAlexander V. Chernikov for ( ; ac != 0; ac--, av++) { 1168ead75a59SLuigi Rizzo if (!strncmp(av[0], "config", strlen(av[0]))) { 1169d6164b77SAlexander V. Chernikov cmd = IP_FW_NAT44_XGETCONFIG; 1170ead75a59SLuigi Rizzo continue; 1171ead75a59SLuigi Rizzo } 1172d6164b77SAlexander V. Chernikov if (strcmp(av[0], "log") == 0) { 1173d6164b77SAlexander V. Chernikov cmd = IP_FW_NAT44_XGETLOG; 1174d6164b77SAlexander V. Chernikov continue; 1175d6164b77SAlexander V. Chernikov } 1176d6164b77SAlexander V. Chernikov if (name != NULL) 1177d6164b77SAlexander V. Chernikov err(EX_USAGE,"only one instance name may be specified"); 1178d6164b77SAlexander V. Chernikov name = av[0]; 1179ead75a59SLuigi Rizzo } 1180ead75a59SLuigi Rizzo 1181d6164b77SAlexander V. Chernikov if (cmd == 0) 1182d6164b77SAlexander V. Chernikov errx(EX_USAGE, "Please specify action. Available: config,log"); 1183d6164b77SAlexander V. Chernikov 1184d6164b77SAlexander V. Chernikov if (name == NULL) { 1185d6164b77SAlexander V. Chernikov memset(&nla, 0, sizeof(nla)); 1186d6164b77SAlexander V. Chernikov nla.cmd = cmd; 1187d6164b77SAlexander V. Chernikov nla.is_all = 1; 1188d6164b77SAlexander V. Chernikov nat_foreach(nat_show_data, &nla, 1); 1189ead75a59SLuigi Rizzo } else { 1190d6164b77SAlexander V. Chernikov if (nat_get_cmd(name, cmd, &oh) != 0) 1191d6164b77SAlexander V. Chernikov err(EX_OSERR, "Error getting nat %s instance info", name); 1192d6164b77SAlexander V. Chernikov nat_show_cfg((struct nat44_cfg_nat *)(oh + 1), NULL); 1193d6164b77SAlexander V. Chernikov free(oh); 1194ead75a59SLuigi Rizzo } 1195ead75a59SLuigi Rizzo } 1196d6164b77SAlexander V. Chernikov 1197