nat_cmd.c revision 58776
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: head/usr.sbin/ppp/nat_cmd.c 58776 2000-03-29 09:31:52Z brian $ 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 59static int StrToAddr(const char *, struct in_addr *); 60static int StrToPortRange(const char *, u_short *, u_short *, const char *); 61static int StrToAddrAndPort(const char *, struct in_addr *, u_short *, 62 u_short *, const char *); 63 64static void 65lowhigh(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 76int 77nat_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 173int 174nat_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 210static int 211StrToAddr(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 228static int 229StrToPort(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 248static int 249StrToPortRange(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 273static int 274StrToAddrAndPort(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 295int 296nat_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 318int 319nat_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 342static struct mbuf * 343nat_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp, 344 int pri, u_short *proto) 345{ 346 if (!bundle->NatEnabled || *proto != PROTO_IP) 347 return bp; 348 349 log_Printf(LogDEBUG, "nat_LayerPush: PROTO_IP -> PROTO_IP\n"); 350 m_settype(bp, MB_NATOUT); 351 /* Ensure there's a bit of extra buffer for the NAT code... */ 352 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 353 PacketAliasOut(MBUF_CTOP(bp), bp->m_len); 354 bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len); 355 356 return bp; 357} 358 359static struct mbuf * 360nat_LayerPull(struct bundle *bundle, struct link *l, struct mbuf *bp, 361 u_short *proto) 362{ 363 static int gfrags; 364 struct ip *pip, *piip; 365 int ret, len, nfrags; 366 struct mbuf **last; 367 char *fptr; 368 369 if (!bundle->NatEnabled || *proto != PROTO_IP) 370 return bp; 371 372 log_Printf(LogDEBUG, "nat_LayerPull: PROTO_IP -> PROTO_IP\n"); 373 m_settype(bp, MB_NATIN); 374 bp = m_pullup(bp); 375 pip = (struct ip *)MBUF_CTOP(bp); 376 piip = (struct ip *)((char *)pip + (pip->ip_hl << 2)); 377 378 if (pip->ip_p == IPPROTO_IGMP || 379 (pip->ip_p == IPPROTO_IPIP && IN_CLASSD(ntohl(piip->ip_dst.s_addr)))) 380 return bp; 381 382 /* Ensure there's a bit of extra buffer for the NAT code... */ 383 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 384 ret = PacketAliasIn(MBUF_CTOP(bp), bp->m_len); 385 pip = (struct ip *)MBUF_CTOP(bp); 386 387 bp->m_len = ntohs(pip->ip_len); 388 if (bp->m_len > MAX_MRU) { 389 log_Printf(LogWARN, "nat_LayerPull: Problem with IP header length (%lu)\n", 390 (unsigned long)bp->m_len); 391 m_freem(bp); 392 return NULL; 393 } 394 395 switch (ret) { 396 case PKT_ALIAS_OK: 397 break; 398 399 case PKT_ALIAS_UNRESOLVED_FRAGMENT: 400 /* Save the data for later */ 401 fptr = malloc(bp->m_len); 402 bp = mbuf_Read(bp, fptr, bp->m_len); 403 PacketAliasSaveFragment(fptr); 404 log_Printf(LogDEBUG, "Store another frag (%lu) - now %d\n", 405 (unsigned long)((struct ip *)fptr)->ip_id, ++gfrags); 406 break; 407 408 case PKT_ALIAS_FOUND_HEADER_FRAGMENT: 409 /* Fetch all the saved fragments and chain them on the end of `bp' */ 410 last = &bp->m_nextpkt; 411 nfrags = 0; 412 while ((fptr = PacketAliasGetFragment(MBUF_CTOP(bp))) != NULL) { 413 nfrags++; 414 PacketAliasFragmentIn(MBUF_CTOP(bp), fptr); 415 len = ntohs(((struct ip *)fptr)->ip_len); 416 *last = m_get(len, MB_NATIN); 417 memcpy(MBUF_CTOP(*last), fptr, len); 418 free(fptr); 419 last = &(*last)->m_nextpkt; 420 } 421 gfrags -= nfrags; 422 log_Printf(LogDEBUG, "Found a frag header (%lu) - plus %d more frags (no" 423 "w %d)\n", (unsigned long)((struct ip *)MBUF_CTOP(bp))->ip_id, 424 nfrags, gfrags); 425 break; 426 427 case PKT_ALIAS_IGNORED: 428 if (log_IsKept(LogTCPIP)) { 429 log_Printf(LogTCPIP, "NAT engine ignored data:\n"); 430 PacketCheck(bundle, (char *)pip, ntohs(pip->ip_len), NULL); 431 } 432 m_freem(bp); 433 bp = NULL; 434 break; 435 436 default: 437 log_Printf(LogWARN, "nat_LayerPull: Dropped a packet (%d)....\n", ret); 438 m_freem(bp); 439 bp = NULL; 440 break; 441 } 442 443 return bp; 444} 445 446struct layer natlayer = 447 { LAYER_NAT, "nat", nat_LayerPush, nat_LayerPull }; 448