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