ip.c revision 31143
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.28 1997/11/12 19:48:45 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#include <netinet/in.h> 28#include <netinet/in_systm.h> 29#include <netinet/ip.h> 30#include <netinet/ip_icmp.h> 31#include <netinet/udp.h> 32#include <netinet/tcp.h> 33#include <arpa/inet.h> 34 35#include <alias.h> 36#include <errno.h> 37#include <stdio.h> 38#include <stdlib.h> 39#include <string.h> 40#include <termios.h> 41#include <unistd.h> 42 43#include "mbuf.h" 44#include "log.h" 45#include "defs.h" 46#include "timer.h" 47#include "fsm.h" 48#include "lcpproto.h" 49#include "hdlc.h" 50#include "loadalias.h" 51#include "command.h" 52#include "vars.h" 53#include "filter.h" 54#include "log.h" 55#include "os.h" 56#include "ipcp.h" 57#include "vjcomp.h" 58#include "lcp.h" 59#include "modem.h" 60#include "ip.h" 61 62static struct pppTimer IdleTimer; 63 64static void 65IdleTimeout() 66{ 67 LogPrintf(LogPHASE, "Idle timer expired.\n"); 68 reconnect(RECON_FALSE); 69 LcpClose(); 70} 71 72/* 73 * Start Idle timer. If timeout is reached, we call LcpClose() to 74 * close LCP and link. 75 */ 76void 77StartIdleTimer() 78{ 79 if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) { 80 StopTimer(&IdleTimer); 81 IdleTimer.func = IdleTimeout; 82 IdleTimer.load = VarIdleTimeout * SECTICKS; 83 IdleTimer.state = TIMER_STOPPED; 84 StartTimer(&IdleTimer); 85 } 86} 87 88void 89UpdateIdleTimer() 90{ 91 if (OsLinkIsUp()) 92 StartIdleTimer(); 93} 94 95void 96StopIdleTimer() 97{ 98 StopTimer(&IdleTimer); 99} 100 101/* 102 * If any IP layer traffic is detected, refresh IdleTimer. 103 */ 104static void 105RestartIdleTimer() 106{ 107 if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) { 108 StartTimer(&IdleTimer); 109 ipIdleSecs = 0; 110 } 111} 112 113static u_short interactive_ports[32] = { 114 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115 0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543, 116}; 117 118#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p)) 119 120static char *TcpFlags[] = { 121 "FIN", "SYN", "RST", "PSH", "ACK", "URG", 122}; 123 124static char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"}; 125static struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters}; 126 127static int 128PortMatch(int op, u_short pport, u_short rport) 129{ 130 switch (op) { 131 case OP_EQ: 132 return (pport == rport); 133 case OP_GT: 134 return (pport > rport); 135 case OP_LT: 136 return (pport < rport); 137 default: 138 return (0); 139 } 140} 141 142/* 143 * Check a packet against with defined filters 144 */ 145static int 146FilterCheck(struct ip * pip, int direction) 147{ 148 struct filterent *fp = Filters[direction]; 149 int gotinfo, cproto, estab, n; 150 struct tcphdr *th; 151 struct udphdr *uh; 152 struct icmp *ih; 153 char *ptop; 154 u_short sport, dport; 155 156 if (fp->action) { 157 cproto = gotinfo = estab = 0; 158 sport = dport = 0; 159 for (n = 0; n < MAXFILTERS; n++) { 160 if (fp->action) { 161 /* permit fragments on in and out filter */ 162 if ((direction == FL_IN || direction == FL_OUT) && 163 (ntohs(pip->ip_off) & IP_OFFMASK) != 0) { 164 return (A_PERMIT); 165 } 166 LogPrintf(LogDEBUG, "rule = %d\n", n); 167 if ((pip->ip_src.s_addr & fp->smask.s_addr) == 168 (fp->saddr.s_addr & fp->smask.s_addr) && 169 (pip->ip_dst.s_addr & fp->dmask.s_addr) == 170 (fp->daddr.s_addr & fp->dmask.s_addr)) { 171 if (fp->proto) { 172 if (!gotinfo) { 173 ptop = (char *) pip + (pip->ip_hl << 2); 174 175 switch (pip->ip_p) { 176 case IPPROTO_ICMP: 177 cproto = P_ICMP; 178 ih = (struct icmp *) ptop; 179 sport = ih->icmp_type; 180 estab = 1; 181 break; 182 case IPPROTO_UDP: 183 cproto = P_UDP; 184 uh = (struct udphdr *) ptop; 185 sport = ntohs(uh->uh_sport); 186 dport = ntohs(uh->uh_dport); 187 estab = 1; 188 break; 189 case IPPROTO_TCP: 190 cproto = P_TCP; 191 th = (struct tcphdr *) ptop; 192 sport = ntohs(th->th_sport); 193 dport = ntohs(th->th_dport); 194 estab = (th->th_flags & TH_ACK); 195 if (estab == 0) 196 LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n", 197 th->th_flags, sport, dport); 198 break; 199 default: 200 return (A_DENY);/* We'll block unknown type of packet */ 201 } 202 gotinfo = 1; 203 LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d," 204 " dstop = %d, estab = %d\n", direction, cproto, 205 fp->opt.srcop, fp->opt.dstop, estab); 206 } 207 LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d," 208 " dport = %d\n", n, cproto, sport, dport); 209 LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action); 210 211 if (cproto == fp->proto) { 212 if ((fp->opt.srcop == OP_NONE || 213 PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) 214 && 215 (fp->opt.dstop == OP_NONE || 216 PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) 217 && 218 (fp->opt.estab == 0 || estab)) { 219 return (fp->action); 220 } 221 } 222 } else { 223 /* Address is mached. Make a decision. */ 224 LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action); 225 return (fp->action); 226 } 227 } 228 } 229 fp++; 230 } 231 return (A_DENY); /* No rule is mached. Deny this packet */ 232 } 233 return (A_PERMIT); /* No rule is given. Permit this packet */ 234} 235 236static void 237IcmpError(struct ip * pip, int code) 238{ 239#ifdef notdef 240 struct mbuf *bp; 241 242 if (pip->ip_p != IPPROTO_ICMP) { 243 bp = mballoc(cnt, MB_IPIN); 244 memcpy(MBUF_CTOP(bp), ptr, cnt); 245 SendPppFrame(bp); 246 RestartIdleTimer(); 247 ipOutOctets += cnt; 248 } 249#endif 250} 251 252/* 253 * For debugging aid. 254 */ 255int 256PacketCheck(char *cp, int nb, int direction) 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 static char logbuf[200]; 267 268 logit = LogIsKept(LogTCPIP); 269 loglen = 0; 270 271 pip = (struct ip *) cp; 272 273 if (logit && loglen < sizeof logbuf) { 274 snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", 275 Direction[direction]); 276 loglen += strlen(logbuf + loglen); 277 } 278 ptop = (cp + (pip->ip_hl << 2)); 279 280 switch (pip->ip_p) { 281 case IPPROTO_ICMP: 282 if (logit && loglen < sizeof logbuf) { 283 icmph = (struct icmp *) ptop; 284 snprintf(logbuf + loglen, sizeof logbuf - loglen, 285 "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 286 loglen += strlen(logbuf + loglen); 287 snprintf(logbuf + loglen, sizeof logbuf - loglen, 288 "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); 289 loglen += strlen(logbuf + loglen); 290 } 291 break; 292 case IPPROTO_UDP: 293 if (logit && loglen < sizeof logbuf) { 294 uh = (struct udphdr *) ptop; 295 snprintf(logbuf + loglen, sizeof logbuf - loglen, 296 "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 297 loglen += strlen(logbuf + loglen); 298 snprintf(logbuf + loglen, sizeof logbuf - loglen, 299 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 300 loglen += strlen(logbuf + loglen); 301 } 302 break; 303 case IPPROTO_TCP: 304 th = (struct tcphdr *) ptop; 305 if (pip->ip_tos == IPTOS_LOWDELAY) 306 pri = PRI_FAST; 307 else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 308 if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) 309 pri = PRI_FAST; 310 } 311 if (logit && loglen < sizeof logbuf) { 312 len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 313 snprintf(logbuf + loglen, sizeof logbuf - loglen, 314 "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 315 loglen += strlen(logbuf + loglen); 316 snprintf(logbuf + loglen, sizeof logbuf - loglen, 317 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 318 loglen += strlen(logbuf + loglen); 319 n = 0; 320 for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 321 if (th->th_flags & mask) { 322 snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 323 loglen += strlen(logbuf + loglen); 324 } 325 n++; 326 } 327 snprintf(logbuf + loglen, sizeof logbuf - loglen, 328 " seq:%x ack:%x (%d/%d)", 329 ntohl(th->th_seq), ntohl(th->th_ack), len, nb); 330 loglen += strlen(logbuf + loglen); 331 if ((th->th_flags & TH_SYN) && nb > 40) { 332 u_short *sp; 333 334 ptop += 20; 335 sp = (u_short *) ptop; 336 if (ntohs(sp[0]) == 0x0204) { 337 snprintf(logbuf + loglen, sizeof logbuf - loglen, 338 " MSS = %d", ntohs(sp[1])); 339 loglen += strlen(logbuf + loglen); 340 } 341 } 342 } 343 break; 344 } 345 346 if ((FilterCheck(pip, direction) & A_DENY)) { 347 if (logit) 348 LogPrintf(LogTCPIP, "%s - BLOCKED\n", logbuf); 349 if (direction == 0) 350 IcmpError(pip, pri); 351 return (-1); 352 } else { 353 if (FilterCheck(pip, FL_KEEP) & A_DENY) { /* Check Keep Alive filter */ 354 if (logit) 355 LogPrintf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf); 356 ipKeepAlive = 0; 357 } else { 358 if (logit) 359 LogPrintf(LogTCPIP, "%s\n", logbuf); 360 ipKeepAlive = 1; 361 } 362 return (pri); 363 } 364} 365 366void 367IpInput(struct mbuf * bp) 368{ /* IN: Pointer to IP pakcet */ 369 u_char *cp; 370 struct mbuf *wp; 371 int nb, nw; 372 u_char tunbuff[MAX_MRU]; 373 374 cp = tunbuff; 375 nb = 0; 376 for (wp = bp; wp; wp = wp->next) { /* Copy to contiguous region */ 377 memcpy(cp, MBUF_CTOP(wp), wp->cnt); 378 cp += wp->cnt; 379 nb += wp->cnt; 380 } 381 382 if (mode & MODE_ALIAS) { 383 int iresult; 384 char *fptr; 385 386 iresult = VarPacketAliasIn(tunbuff, sizeof tunbuff); 387 nb = ntohs(((struct ip *) tunbuff)->ip_len); 388 389 if (nb > MAX_MRU) { 390 LogPrintf(LogERROR, "IpInput: Problem with IP header length\n"); 391 pfree(bp); 392 return; 393 } 394 if (iresult == PKT_ALIAS_OK 395 || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 396 if (PacketCheck(tunbuff, nb, FL_IN) < 0) { 397 pfree(bp); 398 return; 399 } 400 ipInOctets += nb; 401 402 nb = ntohs(((struct ip *) tunbuff)->ip_len); 403 nw = write(tun_out, tunbuff, nb); 404 if (nw != nb) 405 if (nw == -1) 406 LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 407 strerror(errno)); 408 else 409 LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 410 411 if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 412 while ((fptr = VarPacketAliasGetFragment(tunbuff)) != NULL) { 413 VarPacketAliasFragmentIn(tunbuff, fptr); 414 nb = ntohs(((struct ip *) fptr)->ip_len); 415 nw = write(tun_out, fptr, nb); 416 if (nw != nb) 417 if (nw == -1) 418 LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 419 strerror(errno)); 420 else 421 LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 422 free(fptr); 423 } 424 } 425 } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) { 426 nb = ntohs(((struct ip *) tunbuff)->ip_len); 427 fptr = malloc(nb); 428 if (fptr == NULL) 429 LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n"); 430 else { 431 memcpy(fptr, tunbuff, nb); 432 VarPacketAliasSaveFragment(fptr); 433 } 434 } 435 } else { /* no aliasing */ 436 if (PacketCheck(tunbuff, nb, FL_IN) < 0) { 437 pfree(bp); 438 return; 439 } 440 ipInOctets += nb; 441 nw = write(tun_out, tunbuff, nb); 442 if (nw != nb) 443 if (nw == -1) 444 LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno)); 445 else 446 LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 447 } 448 pfree(bp); 449 450 RestartIdleTimer(); 451} 452 453static struct mqueue IpOutputQueues[PRI_FAST + 1]; 454 455void 456IpEnqueue(int pri, char *ptr, int count) 457{ 458 struct mbuf *bp; 459 460 bp = mballoc(count, MB_IPQ); 461 memcpy(MBUF_CTOP(bp), ptr, count); 462 Enqueue(&IpOutputQueues[pri], bp); 463} 464 465#if 0 466int 467IsIpEnqueued() 468{ 469 struct mqueue *queue; 470 int exist = 0; 471 472 for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 473 if (queue->qlen > 0) { 474 exist = 1; 475 break; 476 } 477 } 478 return (exist); 479} 480#endif 481 482void 483IpStartOutput() 484{ 485 struct mqueue *queue; 486 struct mbuf *bp; 487 int cnt; 488 489 if (IpcpFsm.state != ST_OPENED) 490 return; 491 for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 492 if (queue->top) { 493 bp = Dequeue(queue); 494 if (bp) { 495 cnt = plength(bp); 496 SendPppFrame(bp); 497 RestartIdleTimer(); 498 ipOutOctets += cnt; 499 break; 500 } 501 } 502 } 503} 504