1 /* 2 * Copyright (c) 2014 - 2018 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Bill Yuan <bycn82@dragonflybsd.org> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/param.h> 36 #include <sys/mbuf.h> 37 #include <sys/socket.h> 38 #include <sys/sockio.h> 39 #include <sys/sysctl.h> 40 #include <sys/time.h> 41 #include <sys/wait.h> 42 43 #include <arpa/inet.h> 44 #include <ctype.h> 45 #include <dlfcn.h> 46 #include <err.h> 47 #include <errno.h> 48 #include <grp.h> 49 #include <limits.h> 50 #include <netdb.h> 51 #include <pwd.h> 52 #include <sysexits.h> 53 #include <signal.h> 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <stdarg.h> 57 #include <string.h> 58 #include <timeconv.h> 59 #include <unistd.h> 60 61 #include <netinet/in.h> 62 #include <netinet/in_systm.h> 63 #include <netinet/ip.h> 64 #include <netinet/ip_icmp.h> 65 #include <netinet/tcp.h> 66 #include <net/if.h> 67 #include <net/if_dl.h> 68 #include <net/route.h> 69 #include <net/ethernet.h> 70 71 #include <net/ipfw3/ip_fw3.h> 72 #include <net/ipfw3_basic/ip_fw3_table.h> 73 #include <net/ipfw3_basic/ip_fw3_sync.h> 74 #include <net/ipfw3_basic/ip_fw3_basic.h> 75 #include <net/ipfw3_nat/ip_fw3_nat.h> 76 #include <net/dummynet3/ip_dummynet3.h> 77 78 #include "ipfw3.h" 79 #include "ipfw3nat.h" 80 81 extern int verbose; 82 extern int do_time; 83 extern int do_quiet; 84 extern int do_force; 85 86 87 void 88 nat_config_add(int ac, char **av) 89 { 90 struct ioc_nat *ioc; 91 struct in_addr *ip; 92 int error, len = 0; 93 char *id, buf[LEN_NAT_CMD_BUF]; 94 95 memset(buf, 0, LEN_NAT_CMD_BUF); 96 ioc = (struct ioc_nat *)buf; 97 98 NEXT_ARG; 99 if (ac && isdigit(**av)) { 100 id = *av; 101 ioc->id = atoi(*av); 102 if (ioc->id <= 0 || ioc->id > NAT_ID_MAX) { 103 errx(EX_DATAERR, "invalid nat id"); 104 } 105 } else { 106 errx(EX_DATAERR, "missing nat id"); 107 } 108 len += LEN_IOC_NAT; 109 110 NEXT_ARG; 111 if (strncmp(*av, "ip", strlen(*av))) { 112 errx(EX_DATAERR, "missing `ip'"); 113 } 114 NEXT_ARG; 115 ip = &ioc->ip; 116 while (ac > 0){ 117 if (!inet_aton(*av, ip)) { 118 errx(EX_DATAERR, "bad ip addr `%s'", *av); 119 } 120 ioc->count++; 121 len += LEN_IN_ADDR; 122 ip++; 123 NEXT_ARG; 124 } 125 126 error = do_set_x(IP_FW_NAT_ADD, ioc, len); 127 if (error) { 128 err(1, "do_set_x(%s)", "IP_FW_NAT_ADD"); 129 } 130 131 /* show the rule after configured */ 132 int _ac = 2; 133 char *_av[] = {"config", id}; 134 nat_config_get(_ac, _av); 135 } 136 137 void 138 nat_config_show(char *buf, int nbytes, int nat_id) 139 { 140 struct ioc_nat *ioc; 141 struct in_addr *ip; 142 int n, len = 0; 143 144 while (len < nbytes) { 145 ioc = (struct ioc_nat *)(buf + len); 146 if (nat_id == 0 || ioc->id == nat_id) { 147 printf("ipfw3 nat %u config ip", ioc->id); 148 } 149 ip = &ioc->ip; 150 len += LEN_IOC_NAT; 151 for (n = 0; n < ioc->count; n++) { 152 if (nat_id == 0 || ioc->id == nat_id) { 153 printf(" %s", inet_ntoa(*ip)); 154 } 155 ip++; 156 len += LEN_IN_ADDR; 157 } 158 if (nat_id == 0 || ioc->id == nat_id) { 159 printf("\n"); 160 } 161 } 162 } 163 164 void 165 nat_config_get(int ac, char **av) 166 { 167 int nbytes, nalloc; 168 int nat_id; 169 uint8_t *data; 170 171 nalloc = 1024; 172 data = NULL; 173 nat_id = 0; 174 175 NEXT_ARG; 176 if (ac == 1) { 177 nat_id = strtoul(*av, NULL, 10); 178 } 179 180 nbytes = nalloc; 181 while (nbytes >= nalloc) { 182 nalloc = nalloc * 2; 183 nbytes = nalloc; 184 if ((data = realloc(data, nbytes)) == NULL) { 185 err(EX_OSERR, "realloc"); 186 } 187 if (do_get_x(IP_FW_NAT_GET, data, &nbytes) < 0) { 188 err(EX_OSERR, "do_get_x(IP_FW_NAT_GET)"); 189 } 190 } 191 if (nbytes == 0) { 192 exit(EX_OK); 193 } 194 nat_config_show(data, nbytes, nat_id); 195 } 196 197 void 198 nat_config_delete(int ac, char *av[]) 199 { 200 NEXT_ARG; 201 int i = 0; 202 if (ac > 0) { 203 i = atoi(*av); 204 } 205 if (do_set_x(IP_FW_NAT_DEL, &i, sizeof(i)) == -1) 206 errx(EX_USAGE, "NAT %d in use or not exists", i); 207 } 208 209 void 210 nat_state_show(int ac, char **av) 211 { 212 int nbytes, nalloc; 213 int nat_id; 214 uint8_t *data; 215 216 nalloc = 1024; 217 data = NULL; 218 219 NEXT_ARG; 220 if (ac == 0) 221 nat_id = 0; 222 else 223 nat_id = strtoul(*av, NULL, 10); 224 225 nbytes = nalloc; 226 while (nbytes >= nalloc) { 227 nalloc = nalloc * 2; 228 nbytes = nalloc; 229 if ((data = realloc(data, nbytes)) == NULL) { 230 err(EX_OSERR, "realloc"); 231 } 232 memcpy(data, &nat_id, sizeof(int)); 233 if (do_get_x(IP_FW_NAT_GET_RECORD, data, &nbytes) < 0) { 234 err(EX_OSERR, "do_get_x(IP_FW_NAT_GET_RECORD)"); 235 } 236 } 237 if (nbytes == 0) 238 exit(EX_OK); 239 240 struct ioc_nat_state *ioc; 241 ioc =(struct ioc_nat_state *)data; 242 int count = nbytes / LEN_IOC_NAT_STATE; 243 int i; 244 for (i = 0; i < count; i ++) { 245 printf("%d %d", ioc->nat_id, ioc->cpu_id); 246 if (ioc->proto == IPPROTO_ICMP) { 247 printf(" icmp"); 248 } else if (ioc->proto == IPPROTO_TCP) { 249 printf(" tcp"); 250 } else if (ioc->proto == IPPROTO_UDP) { 251 printf(" udp"); 252 } 253 printf(" %s:%hu",inet_ntoa(ioc->src_addr), 254 htons(ioc->src_port)); 255 printf(" %s:%hu",inet_ntoa(ioc->alias_addr), 256 htons(ioc->alias_port)); 257 printf(" %s:%hu",inet_ntoa(ioc->dst_addr), 258 htons(ioc->dst_port)); 259 printf(" %c", ioc->direction? 'o' : 'i'); 260 printf(" %lld", (long long)ioc->life); 261 printf("\n"); 262 ioc++; 263 } 264 } 265 266 void 267 nat_config_flush(void) 268 { 269 int cmd = IP_FW_NAT_FLUSH; 270 if (!do_force) { 271 int c; 272 273 printf("Are you sure? [yn] "); 274 fflush(stdout); 275 do { 276 c = toupper(getc(stdin)); 277 while (c != '\n' && getc(stdin) != '\n') 278 if (feof(stdin)) 279 return; /* and do not flush */ 280 } while (c != 'Y' && c != 'N'); 281 if (c == 'N') /* user said no */ 282 return; 283 } 284 if (do_set_x(cmd, NULL, 0) < 0 ) { 285 errx(EX_USAGE, "NAT configuration in use"); 286 } 287 if (!do_quiet) { 288 printf("Flushed all nat configurations"); 289 } 290 } 291 292 void 293 nat_main(int ac, char **av) 294 { 295 if (!strncmp(*av, "config", strlen(*av))) { 296 nat_config_add(ac, av); 297 } else if (!strncmp(*av, "flush", strlen(*av))) { 298 nat_config_flush(); 299 } else if (!strncmp(*av, "show", strlen(*av))) { 300 if (ac > 2 && isdigit(*(av[1]))) { 301 char *p = av[1]; 302 av[1] = av[2]; 303 av[2] = p; 304 } 305 NEXT_ARG; 306 if (!strncmp(*av, "config", strlen(*av))) { 307 nat_config_get(ac, av); 308 } else if (!strncmp(*av, "state", strlen(*av))) { 309 nat_state_show(ac,av); 310 } else { 311 errx(EX_USAGE, "bad nat show command `%s'", *av); 312 } 313 } else if (!strncmp(*av, "delete", strlen(*av))) { 314 nat_config_delete(ac, av); 315 } else { 316 errx(EX_USAGE, "bad ipfw nat command `%s'", *av); 317 } 318 } 319