ip.c revision 48142
1/* 2 * PPP IP Protocol Interface 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $Id: ip.c,v 1.63 1999/06/02 15:59:00 brian Exp $ 21 * 22 * TODO: 23 * o Return ICMP message for filterd packet 24 * and optionaly record it into log. 25 */ 26#include <sys/param.h> 27#if defined(__OpenBSD__) || defined(__NetBSD__) 28#include <sys/socket.h> 29#endif 30#include <netinet/in.h> 31#include <netinet/in_systm.h> 32#include <netinet/ip.h> 33#include <netinet/ip_icmp.h> 34#include <netinet/udp.h> 35#include <netinet/tcp.h> 36#include <arpa/inet.h> 37#include <sys/un.h> 38 39#include <errno.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <termios.h> 44#include <unistd.h> 45 46#include "layer.h" 47#include "proto.h" 48#include "mbuf.h" 49#include "log.h" 50#include "defs.h" 51#include "timer.h" 52#include "fsm.h" 53#include "lqr.h" 54#include "hdlc.h" 55#include "throughput.h" 56#include "iplist.h" 57#include "slcompress.h" 58#include "ipcp.h" 59#include "filter.h" 60#include "descriptor.h" 61#include "lcp.h" 62#include "ccp.h" 63#include "link.h" 64#include "mp.h" 65#ifndef NORADIUS 66#include "radius.h" 67#endif 68#include "bundle.h" 69#include "vjcomp.h" 70#include "tun.h" 71#include "ip.h" 72 73static const u_short interactive_ports[32] = { 74 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75 80, 81, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543, 76}; 77 78#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p)) 79 80static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" }; 81 82static int 83PortMatch(int op, u_short pport, u_short rport) 84{ 85 switch (op) { 86 case OP_EQ: 87 return (pport == rport); 88 case OP_GT: 89 return (pport > rport); 90 case OP_LT: 91 return (pport < rport); 92 default: 93 return (0); 94 } 95} 96 97/* 98 * Check a packet against a defined filter 99 */ 100static int 101FilterCheck(struct ip *pip, struct filter *filter) 102{ 103 int gotinfo, cproto, estab, syn, finrst, n, len, didname; 104 struct tcphdr *th; 105 struct udphdr *uh; 106 struct icmp *ih; 107 char *ptop; 108 u_short sport, dport; 109 struct filterent *fp = filter->rule; 110 char dbuff[100]; 111 112 if (fp->action) { 113 cproto = gotinfo = estab = syn = finrst = didname = 0; 114 sport = dport = 0; 115 for (n = 0; n < MAXFILTERS; n++) { 116 if (fp->action != A_NONE) { 117 /* permit fragments on in and out filter */ 118 if (filter->fragok && (ntohs(pip->ip_off) & IP_OFFMASK) != 0) 119 return (A_PERMIT); 120 121 if (!didname) 122 log_Printf(LogDEBUG, "%s filter:\n", filter->name); 123 didname = 1; 124 125 if ((pip->ip_src.s_addr & fp->src.mask.s_addr) == 126 (fp->src.ipaddr.s_addr & fp->src.mask.s_addr) && 127 (pip->ip_dst.s_addr & fp->dst.mask.s_addr) == 128 (fp->dst.ipaddr.s_addr & fp->dst.mask.s_addr)) { 129 if (fp->proto) { 130 if (!gotinfo) { 131 ptop = (char *) pip + (pip->ip_hl << 2); 132 133 switch (pip->ip_p) { 134 case IPPROTO_ICMP: 135 cproto = P_ICMP; 136 ih = (struct icmp *) ptop; 137 sport = ih->icmp_type; 138 estab = syn = finrst = -1; 139 if (log_IsKept(LogDEBUG)) 140 snprintf(dbuff, sizeof dbuff, "sport = %d", sport); 141 break; 142 case IPPROTO_IGMP: 143 cproto = P_IGMP; 144 estab = syn = finrst = -1; 145 sport = ntohs(0); 146 break; 147 case IPPROTO_UDP: 148 case IPPROTO_IPIP: 149 cproto = P_UDP; 150 uh = (struct udphdr *) ptop; 151 sport = ntohs(uh->uh_sport); 152 dport = ntohs(uh->uh_dport); 153 estab = syn = finrst = -1; 154 if (log_IsKept(LogDEBUG)) 155 snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d", 156 sport, dport); 157 break; 158 case IPPROTO_TCP: 159 cproto = P_TCP; 160 th = (struct tcphdr *) ptop; 161 sport = ntohs(th->th_sport); 162 dport = ntohs(th->th_dport); 163 estab = (th->th_flags & TH_ACK); 164 syn = (th->th_flags & TH_SYN); 165 finrst = (th->th_flags & (TH_FIN|TH_RST)); 166 if (log_IsKept(LogDEBUG)) { 167 if (!estab) 168 snprintf(dbuff, sizeof dbuff, 169 "flags = %02x, sport = %d, dport = %d", 170 th->th_flags, sport, dport); 171 else 172 *dbuff = '\0'; 173 } 174 break; 175 default: 176 return (A_DENY); /* We'll block unknown type of packet */ 177 } 178 if (log_IsKept(LogDEBUG)) { 179 if (estab != -1) { 180 len = strlen(dbuff); 181 snprintf(dbuff + len, sizeof dbuff - len, 182 ", estab = %d, syn = %d, finrst = %d", 183 estab, syn, finrst); 184 } 185 log_Printf(LogDEBUG, " Filter: proto = %s, %s\n", 186 filter_Proto2Nam(cproto), dbuff); 187 } 188 gotinfo = 1; 189 } 190 if (log_IsKept(LogDEBUG)) { 191 if (fp->opt.srcop != OP_NONE) { 192 snprintf(dbuff, sizeof dbuff, ", src %s %d", 193 filter_Op2Nam(fp->opt.srcop), fp->opt.srcport); 194 len = strlen(dbuff); 195 } else 196 len = 0; 197 if (fp->opt.dstop != OP_NONE) { 198 snprintf(dbuff + len, sizeof dbuff - len, 199 ", dst %s %d", filter_Op2Nam(fp->opt.dstop), 200 fp->opt.dstport); 201 } else if (!len) 202 *dbuff = '\0'; 203 204 log_Printf(LogDEBUG, " rule = %d: Address match, " 205 "check against proto %s%s, action = %s\n", 206 n, filter_Proto2Nam(fp->proto), 207 dbuff, filter_Action2Nam(fp->action)); 208 } 209 210 if (cproto == fp->proto) { 211 if ((fp->opt.srcop == OP_NONE || 212 PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) && 213 (fp->opt.dstop == OP_NONE || 214 PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) && 215 (fp->opt.estab == 0 || estab) && 216 (fp->opt.syn == 0 || syn) && 217 (fp->opt.finrst == 0 || finrst)) { 218 return (fp->action); 219 } 220 } 221 } else { 222 /* Address is mached. Make a decision. */ 223 log_Printf(LogDEBUG, " rule = %d: Address match, action = %s\n", n, 224 filter_Action2Nam(fp->action)); 225 return (fp->action); 226 } 227 } else 228 log_Printf(LogDEBUG, " rule = %d: Address mismatch\n", n); 229 } 230 fp++; 231 } 232 return (A_DENY); /* No rule is mached. Deny this packet */ 233 } 234 return (A_PERMIT); /* No rule is given. Permit this packet */ 235} 236 237#ifdef notdef 238static void 239IcmpError(struct ip *pip, int code) 240{ 241 struct mbuf *bp; 242 243 if (pip->ip_p != IPPROTO_ICMP) { 244 bp = mbuf_Alloc(cnt, MB_IPIN); 245 memcpy(MBUF_CTOP(bp), ptr, cnt); 246 vj_SendFrame(bp); 247 ipcp_AddOutOctets(cnt); 248 } 249} 250#endif 251 252/* 253 * For debugging aid. 254 */ 255int 256PacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter) 257{ 258 struct ip *pip; 259 struct tcphdr *th; 260 struct udphdr *uh; 261 struct icmp *icmph; 262 char *ptop; 263 int mask, len, n; 264 int pri = PRI_NORMAL; 265 int logit, loglen; 266 char logbuf[200]; 267 268 logit = log_IsKept(LogTCPIP) && filter->logok; 269 loglen = 0; 270 271 pip = (struct ip *) cp; 272 273 if (logit && loglen < sizeof logbuf) { 274 snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name); 275 loglen += strlen(logbuf + loglen); 276 } 277 ptop = (cp + (pip->ip_hl << 2)); 278 279 switch (pip->ip_p) { 280 case IPPROTO_ICMP: 281 if (logit && loglen < sizeof logbuf) { 282 icmph = (struct icmp *) ptop; 283 snprintf(logbuf + loglen, sizeof logbuf - loglen, 284 "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 285 loglen += strlen(logbuf + loglen); 286 snprintf(logbuf + loglen, sizeof logbuf - loglen, 287 "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); 288 loglen += strlen(logbuf + loglen); 289 } 290 break; 291 case IPPROTO_UDP: 292 if (logit && loglen < sizeof logbuf) { 293 uh = (struct udphdr *) ptop; 294 snprintf(logbuf + loglen, sizeof logbuf - loglen, 295 "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 296 loglen += strlen(logbuf + loglen); 297 snprintf(logbuf + loglen, sizeof logbuf - loglen, 298 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 299 loglen += strlen(logbuf + loglen); 300 } 301 break; 302 case IPPROTO_IPIP: 303 if (logit && loglen < sizeof logbuf) { 304 uh = (struct udphdr *) ptop; 305 snprintf(logbuf + loglen, sizeof logbuf - loglen, 306 "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 307 loglen += strlen(logbuf + loglen); 308 snprintf(logbuf + loglen, sizeof logbuf - loglen, 309 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 310 loglen += strlen(logbuf + loglen); 311 } 312 break; 313 case IPPROTO_IGMP: 314 if (logit && loglen < sizeof logbuf) { 315 uh = (struct udphdr *) ptop; 316 snprintf(logbuf + loglen, sizeof logbuf - loglen, 317 "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 318 loglen += strlen(logbuf + loglen); 319 snprintf(logbuf + loglen, sizeof logbuf - loglen, 320 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 321 loglen += strlen(logbuf + loglen); 322 } 323 break; 324 case IPPROTO_TCP: 325 th = (struct tcphdr *) ptop; 326 if (pip->ip_tos == IPTOS_LOWDELAY) 327 pri = PRI_FAST; 328 else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 329 if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) 330 pri = PRI_FAST; 331 } 332 if (logit && loglen < sizeof logbuf) { 333 len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 334 snprintf(logbuf + loglen, sizeof logbuf - loglen, 335 "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 336 loglen += strlen(logbuf + loglen); 337 snprintf(logbuf + loglen, sizeof logbuf - loglen, 338 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 339 loglen += strlen(logbuf + loglen); 340 n = 0; 341 for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 342 if (th->th_flags & mask) { 343 snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 344 loglen += strlen(logbuf + loglen); 345 } 346 n++; 347 } 348 snprintf(logbuf + loglen, sizeof logbuf - loglen, 349 " seq:%lx ack:%lx (%d/%d)", 350 (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb); 351 loglen += strlen(logbuf + loglen); 352 if ((th->th_flags & TH_SYN) && nb > 40) { 353 u_short *sp; 354 355 ptop += 20; 356 sp = (u_short *) ptop; 357 if (ntohs(sp[0]) == 0x0204) { 358 snprintf(logbuf + loglen, sizeof logbuf - loglen, 359 " MSS = %d", ntohs(sp[1])); 360 loglen += strlen(logbuf + loglen); 361 } 362 } 363 } 364 break; 365 } 366 367 if ((FilterCheck(pip, filter) & A_DENY)) { 368 if (logit) 369 log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf); 370#ifdef notdef 371 if (direction == 0) 372 IcmpError(pip, pri); 373#endif 374 return (-1); 375 } else { 376 /* Check Keep Alive filter */ 377 if (logit) { 378 if (FilterCheck(pip, &bundle->filter.alive) & A_DENY) 379 log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf); 380 else 381 log_Printf(LogTCPIP, "%s\n", logbuf); 382 } 383 return (pri); 384 } 385} 386 387struct mbuf * 388ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 389{ 390 int nb, nw; 391 struct tun_data tun; 392 struct ip *pip; 393 394 if (bundle->ncp.ipcp.fsm.state != ST_OPENED) { 395 log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n"); 396 mbuf_Free(bp); 397 return NULL; 398 } 399 400 mbuf_SetType(bp, MB_IPIN); 401 tun_fill_header(tun, AF_INET); 402 nb = mbuf_Length(bp); 403 if (nb > sizeof tun.data) { 404 log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n", 405 l->name, nb, (int)(sizeof tun.data)); 406 mbuf_Free(bp); 407 return NULL; 408 } 409 mbuf_Read(bp, tun.data, nb); 410 411 if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) 412 return NULL; 413 414 pip = (struct ip *)tun.data; 415 if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY)) 416 bundle_StartIdleTimer(bundle); 417 418 ipcp_AddInOctets(&bundle->ncp.ipcp, nb); 419 420 nb += sizeof tun - sizeof tun.data; 421 nw = write(bundle->dev.fd, &tun, nb); 422 if (nw != nb) { 423 if (nw == -1) 424 log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n", 425 l->name, nb, strerror(errno)); 426 else 427 log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw); 428 } 429 430 return NULL; 431} 432 433void 434ip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count) 435{ 436 struct mbuf *bp; 437 438 if (pri < 0 || pri > sizeof ipcp->Queue / sizeof ipcp->Queue[0]) 439 log_Printf(LogERROR, "Can't store in ip queue %d\n", pri); 440 else { 441 /* 442 * We allocate an extra 6 bytes, four at the front and two at the end. 443 * This is an optimisation so that we need to do less work in 444 * mbuf_Prepend() in acf_LayerPush() and proto_LayerPush() and 445 * appending in hdlc_LayerPush(). 446 */ 447 bp = mbuf_Alloc(count + 6, MB_IPOUT); 448 bp->offset += 4; 449 bp->cnt -= 6; 450 memcpy(MBUF_CTOP(bp), ptr, count); 451 mbuf_Enqueue(&ipcp->Queue[pri], bp); 452 } 453} 454 455void 456ip_DeleteQueue(struct ipcp *ipcp) 457{ 458 struct mqueue *queue; 459 460 for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++) 461 while (queue->top) 462 mbuf_Free(mbuf_Dequeue(queue)); 463} 464 465int 466ip_QueueLen(struct ipcp *ipcp) 467{ 468 struct mqueue *queue; 469 int result = 0; 470 471 for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++) 472 result += queue->qlen; 473 474 return result; 475} 476 477int 478ip_PushPacket(struct link *l, struct bundle *bundle) 479{ 480 struct ipcp *ipcp = &bundle->ncp.ipcp; 481 struct mqueue *queue; 482 struct mbuf *bp; 483 struct ip *pip; 484 int cnt; 485 486 if (ipcp->fsm.state != ST_OPENED) 487 return 0; 488 489 for (queue = &ipcp->Queue[PRI_FAST]; queue >= ipcp->Queue; queue--) 490 if (queue->top) { 491 bp = mbuf_Contiguous(mbuf_Dequeue(queue)); 492 cnt = mbuf_Length(bp); 493 pip = (struct ip *)MBUF_CTOP(bp); 494 if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY)) 495 bundle_StartIdleTimer(bundle); 496 link_PushPacket(l, bp, bundle, PRI_NORMAL, PROTO_IP); 497 ipcp_AddOutOctets(ipcp, cnt); 498 return 1; 499 } 500 501 return 0; 502} 503