1 /*- 2 * The code in this file was written by Eivind Eklund <perhaps@yes.no>, 3 * who places it in the public domain without restriction. 4 * 5 * $FreeBSD$ 6 */ 7 8 #include <sys/param.h> 9 #include <netinet/in.h> 10 #include <arpa/inet.h> 11 #include <netdb.h> 12 #include <netinet/in_systm.h> 13 #include <netinet/in.h> 14 #include <netinet/ip.h> 15 #include <sys/un.h> 16 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <string.h> 20 #include <termios.h> 21 22 #ifdef LOCALNAT 23 #include "alias.h" 24 #else 25 #include <alias.h> 26 #endif 27 28 #include "layer.h" 29 #include "proto.h" 30 #include "defs.h" 31 #include "command.h" 32 #include "log.h" 33 #include "nat_cmd.h" 34 #include "descriptor.h" 35 #include "prompt.h" 36 #include "timer.h" 37 #include "fsm.h" 38 #include "slcompress.h" 39 #include "throughput.h" 40 #include "iplist.h" 41 #include "mbuf.h" 42 #include "lqr.h" 43 #include "hdlc.h" 44 #include "ipcp.h" 45 #include "lcp.h" 46 #include "ccp.h" 47 #include "link.h" 48 #include "mp.h" 49 #include "filter.h" 50 #ifndef NORADIUS 51 #include "radius.h" 52 #endif 53 #include "ip.h" 54 #include "bundle.h" 55 56 57 #define NAT_EXTRABUF (13) 58 59 static int StrToAddr(const char *, struct in_addr *); 60 static int StrToPortRange(const char *, u_short *, u_short *, const char *); 61 static int StrToAddrAndPort(const char *, struct in_addr *, u_short *, 62 u_short *, const char *); 63 64 static void 65 lowhigh(u_short *a, u_short *b) 66 { 67 if (a > b) { 68 u_short c; 69 70 c = *b; 71 *b = *a; 72 *a = c; 73 } 74 } 75 76 int 77 nat_RedirectPort(struct cmdargs const *arg) 78 { 79 if (!arg->bundle->NatEnabled) { 80 prompt_Printf(arg->prompt, "Alias not enabled\n"); 81 return 1; 82 } else if (arg->argc == arg->argn + 3 || arg->argc == arg->argn + 4) { 83 char proto_constant; 84 const char *proto; 85 struct in_addr localaddr; 86 u_short hlocalport, llocalport; 87 struct in_addr aliasaddr; 88 u_short haliasport, laliasport; 89 struct in_addr remoteaddr; 90 u_short hremoteport, lremoteport; 91 struct alias_link *link; 92 int error; 93 94 proto = arg->argv[arg->argn]; 95 if (strcmp(proto, "tcp") == 0) { 96 proto_constant = IPPROTO_TCP; 97 } else if (strcmp(proto, "udp") == 0) { 98 proto_constant = IPPROTO_UDP; 99 } else { 100 prompt_Printf(arg->prompt, "port redirect: protocol must be" 101 " tcp or udp\n"); 102 return -1; 103 } 104 105 error = StrToAddrAndPort(arg->argv[arg->argn+1], &localaddr, &llocalport, 106 &hlocalport, proto); 107 if (error) { 108 prompt_Printf(arg->prompt, "nat port: error reading localaddr:port\n"); 109 return -1; 110 } 111 112 error = StrToPortRange(arg->argv[arg->argn+2], &laliasport, &haliasport, 113 proto); 114 if (error) { 115 prompt_Printf(arg->prompt, "nat port: error reading alias port\n"); 116 return -1; 117 } 118 aliasaddr.s_addr = INADDR_ANY; 119 120 if (arg->argc == arg->argn + 4) { 121 error = StrToAddrAndPort(arg->argv[arg->argn+3], &remoteaddr, 122 &lremoteport, &hremoteport, proto); 123 if (error) { 124 prompt_Printf(arg->prompt, "nat port: error reading " 125 "remoteaddr:port\n"); 126 return -1; 127 } 128 } else { 129 remoteaddr.s_addr = INADDR_ANY; 130 lremoteport = hremoteport = 0; 131 } 132 133 lowhigh(&llocalport, &hlocalport); 134 lowhigh(&laliasport, &haliasport); 135 lowhigh(&lremoteport, &hremoteport); 136 137 if (haliasport - laliasport != hlocalport - llocalport) { 138 prompt_Printf(arg->prompt, "nat port: local & alias port ranges " 139 "are not equal\n"); 140 return -1; 141 } 142 143 if (hremoteport && hremoteport - lremoteport != hlocalport - llocalport) { 144 prompt_Printf(arg->prompt, "nat port: local & remote port ranges " 145 "are not equal\n"); 146 return -1; 147 } 148 149 while (laliasport <= haliasport) { 150 link = PacketAliasRedirectPort(localaddr, htons(llocalport), 151 remoteaddr, htons(lremoteport), 152 aliasaddr, htons(laliasport), 153 proto_constant); 154 155 if (link == NULL) { 156 prompt_Printf(arg->prompt, "nat port: %d: error %d\n", laliasport, 157 error); 158 return 1; 159 } 160 llocalport++; 161 laliasport++; 162 if (hremoteport) 163 lremoteport++; 164 } 165 166 return 0; 167 } 168 169 return -1; 170 } 171 172 173 int 174 nat_RedirectAddr(struct cmdargs const *arg) 175 { 176 if (!arg->bundle->NatEnabled) { 177 prompt_Printf(arg->prompt, "nat not enabled\n"); 178 return 1; 179 } else if (arg->argc == arg->argn+2) { 180 int error; 181 struct in_addr localaddr, aliasaddr; 182 struct alias_link *link; 183 184 error = StrToAddr(arg->argv[arg->argn], &localaddr); 185 if (error) { 186 prompt_Printf(arg->prompt, "address redirect: invalid local address\n"); 187 return 1; 188 } 189 error = StrToAddr(arg->argv[arg->argn+1], &aliasaddr); 190 if (error) { 191 prompt_Printf(arg->prompt, "address redirect: invalid alias address\n"); 192 prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 193 arg->cmd->syntax); 194 return 1; 195 } 196 link = PacketAliasRedirectAddr(localaddr, aliasaddr); 197 if (link == NULL) { 198 prompt_Printf(arg->prompt, "address redirect: packet aliasing" 199 " engine error\n"); 200 prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 201 arg->cmd->syntax); 202 } 203 } else 204 return -1; 205 206 return 0; 207 } 208 209 210 static int 211 StrToAddr(const char *str, struct in_addr *addr) 212 { 213 struct hostent *hp; 214 215 if (inet_aton(str, addr)) 216 return 0; 217 218 hp = gethostbyname(str); 219 if (!hp) { 220 log_Printf(LogWARN, "StrToAddr: Unknown host %s.\n", str); 221 return -1; 222 } 223 *addr = *((struct in_addr *) hp->h_addr); 224 return 0; 225 } 226 227 228 static int 229 StrToPort(const char *str, u_short *port, const char *proto) 230 { 231 struct servent *sp; 232 char *end; 233 234 *port = strtol(str, &end, 10); 235 if (*end != '\0') { 236 sp = getservbyname(str, proto); 237 if (sp == NULL) { 238 log_Printf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n", 239 str, proto); 240 return -1; 241 } 242 *port = ntohs(sp->s_port); 243 } 244 245 return 0; 246 } 247 248 static int 249 StrToPortRange(const char *str, u_short *low, u_short *high, const char *proto) 250 { 251 char *minus; 252 int res; 253 254 minus = strchr(str, '-'); 255 if (minus) 256 *minus = '\0'; /* Cheat the const-ness ! */ 257 258 res = StrToPort(str, low, proto); 259 260 if (minus) 261 *minus = '-'; /* Cheat the const-ness ! */ 262 263 if (res == 0) { 264 if (minus) 265 res = StrToPort(minus + 1, high, proto); 266 else 267 *high = *low; 268 } 269 270 return res; 271 } 272 273 static int 274 StrToAddrAndPort(const char *str, struct in_addr *addr, u_short *low, 275 u_short *high, const char *proto) 276 { 277 char *colon; 278 int res; 279 280 colon = strchr(str, ':'); 281 if (!colon) { 282 log_Printf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str); 283 return -1; 284 } 285 286 *colon = '\0'; /* Cheat the const-ness ! */ 287 res = StrToAddr(str, addr); 288 *colon = ':'; /* Cheat the const-ness ! */ 289 if (res != 0) 290 return -1; 291 292 return StrToPortRange(colon + 1, low, high, proto); 293 } 294 295 int 296 nat_ProxyRule(struct cmdargs const *arg) 297 { 298 char cmd[LINE_LEN]; 299 int f, pos; 300 size_t len; 301 302 if (arg->argn >= arg->argc) 303 return -1; 304 305 for (f = arg->argn, pos = 0; f < arg->argc; f++) { 306 len = strlen(arg->argv[f]); 307 if (sizeof cmd - pos < len + (f ? 1 : 0)) 308 break; 309 if (f) 310 cmd[pos++] = ' '; 311 strcpy(cmd + pos, arg->argv[f]); 312 pos += len; 313 } 314 315 return PacketAliasProxyRule(cmd); 316 } 317 318 int 319 nat_Pptp(struct cmdargs const *arg) 320 { 321 struct in_addr addr; 322 323 if (arg->argc == arg->argn) { 324 addr.s_addr = INADDR_NONE; 325 PacketAliasPptp(addr); 326 return 0; 327 } 328 329 if (arg->argc != arg->argn + 1) 330 return -1; 331 332 addr = GetIpAddr(arg->argv[arg->argn]); 333 if (addr.s_addr == INADDR_NONE) { 334 log_Printf(LogWARN, "%s: invalid address\n", arg->argv[arg->argn]); 335 return 1; 336 } 337 338 PacketAliasPptp(addr); 339 return 0; 340 } 341 342 int 343 nat_SetTarget(struct cmdargs const *arg) 344 { 345 struct in_addr addr; 346 347 if (arg->argc == arg->argn) { 348 addr.s_addr = INADDR_NONE; 349 PacketAliasSetTarget(addr); 350 return 0; 351 } 352 353 if (arg->argc != arg->argn + 1) 354 return -1; 355 356 addr = GetIpAddr(arg->argv[arg->argn]); 357 if (addr.s_addr == INADDR_NONE) { 358 log_Printf(LogWARN, "%s: invalid address\n", arg->argv[arg->argn]); 359 return 1; 360 } 361 362 PacketAliasSetTarget(addr); 363 return 0; 364 } 365 366 static struct mbuf * 367 nat_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp, 368 int pri, u_short *proto) 369 { 370 if (!bundle->NatEnabled || *proto != PROTO_IP) 371 return bp; 372 373 log_Printf(LogDEBUG, "nat_LayerPush: PROTO_IP -> PROTO_IP\n"); 374 m_settype(bp, MB_NATOUT); 375 /* Ensure there's a bit of extra buffer for the NAT code... */ 376 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 377 PacketAliasOut(MBUF_CTOP(bp), bp->m_len); 378 bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len); 379 380 return bp; 381 } 382 383 static struct mbuf * 384 nat_LayerPull(struct bundle *bundle, struct link *l, struct mbuf *bp, 385 u_short *proto) 386 { 387 static int gfrags; 388 struct ip *pip, *piip; 389 int ret, len, nfrags; 390 struct mbuf **last; 391 char *fptr; 392 393 if (!bundle->NatEnabled || *proto != PROTO_IP) 394 return bp; 395 396 log_Printf(LogDEBUG, "nat_LayerPull: PROTO_IP -> PROTO_IP\n"); 397 m_settype(bp, MB_NATIN); 398 bp = m_pullup(bp); 399 pip = (struct ip *)MBUF_CTOP(bp); 400 piip = (struct ip *)((char *)pip + (pip->ip_hl << 2)); 401 402 if (pip->ip_p == IPPROTO_IGMP || 403 (pip->ip_p == IPPROTO_IPIP && IN_CLASSD(ntohl(piip->ip_dst.s_addr)))) 404 return bp; 405 406 /* Ensure there's a bit of extra buffer for the NAT code... */ 407 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 408 ret = PacketAliasIn(MBUF_CTOP(bp), bp->m_len); 409 pip = (struct ip *)MBUF_CTOP(bp); 410 411 bp->m_len = ntohs(pip->ip_len); 412 if (bp->m_len > MAX_MRU) { 413 log_Printf(LogWARN, "nat_LayerPull: Problem with IP header length (%lu)\n", 414 (unsigned long)bp->m_len); 415 m_freem(bp); 416 return NULL; 417 } 418 419 switch (ret) { 420 case PKT_ALIAS_OK: 421 break; 422 423 case PKT_ALIAS_UNRESOLVED_FRAGMENT: 424 /* Save the data for later */ 425 fptr = malloc(bp->m_len); 426 bp = mbuf_Read(bp, fptr, bp->m_len); 427 PacketAliasSaveFragment(fptr); 428 log_Printf(LogDEBUG, "Store another frag (%lu) - now %d\n", 429 (unsigned long)((struct ip *)fptr)->ip_id, ++gfrags); 430 break; 431 432 case PKT_ALIAS_FOUND_HEADER_FRAGMENT: 433 /* Fetch all the saved fragments and chain them on the end of `bp' */ 434 last = &bp->m_nextpkt; 435 nfrags = 0; 436 while ((fptr = PacketAliasGetFragment(MBUF_CTOP(bp))) != NULL) { 437 nfrags++; 438 PacketAliasFragmentIn(MBUF_CTOP(bp), fptr); 439 len = ntohs(((struct ip *)fptr)->ip_len); 440 *last = m_get(len, MB_NATIN); 441 memcpy(MBUF_CTOP(*last), fptr, len); 442 free(fptr); 443 last = &(*last)->m_nextpkt; 444 } 445 gfrags -= nfrags; 446 log_Printf(LogDEBUG, "Found a frag header (%lu) - plus %d more frags (no" 447 "w %d)\n", (unsigned long)((struct ip *)MBUF_CTOP(bp))->ip_id, 448 nfrags, gfrags); 449 break; 450 451 case PKT_ALIAS_IGNORED: 452 if (log_IsKept(LogTCPIP)) { 453 log_Printf(LogTCPIP, "NAT engine ignored data:\n"); 454 PacketCheck(bundle, (char *)pip, ntohs(pip->ip_len), NULL); 455 } 456 m_freem(bp); 457 bp = NULL; 458 break; 459 460 default: 461 log_Printf(LogWARN, "nat_LayerPull: Dropped a packet (%d)....\n", ret); 462 m_freem(bp); 463 bp = NULL; 464 break; 465 } 466 467 return bp; 468 } 469 470 struct layer natlayer = 471 { LAYER_NAT, "nat", nat_LayerPush, nat_LayerPull }; 472