ip.c revision 30733
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.26 1997/10/26 01:02:52 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) == fp->saddr.s_addr 168 && (pip->ip_dst.s_addr & fp->dmask.s_addr) == fp->daddr.s_addr) { 169 if (fp->proto) { 170 if (!gotinfo) { 171 ptop = (char *) pip + (pip->ip_hl << 2); 172 173 switch (pip->ip_p) { 174 case IPPROTO_ICMP: 175 cproto = P_ICMP; 176 ih = (struct icmp *) ptop; 177 sport = ih->icmp_type; 178 estab = 1; 179 break; 180 case IPPROTO_UDP: 181 cproto = P_UDP; 182 uh = (struct udphdr *) ptop; 183 sport = ntohs(uh->uh_sport); 184 dport = ntohs(uh->uh_dport); 185 estab = 1; 186 break; 187 case IPPROTO_TCP: 188 cproto = P_TCP; 189 th = (struct tcphdr *) ptop; 190 sport = ntohs(th->th_sport); 191 dport = ntohs(th->th_dport); 192 estab = (th->th_flags & TH_ACK); 193 if (estab == 0) 194 LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n", 195 th->th_flags, sport, dport); 196 break; 197 default: 198 return (A_DENY);/* We'll block unknown type of packet */ 199 } 200 gotinfo = 1; 201 LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d," 202 " dstop = %d, estab = %d\n", direction, cproto, 203 fp->opt.srcop, fp->opt.dstop, estab); 204 } 205 LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d," 206 " dport = %d\n", n, cproto, sport, dport); 207 LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action); 208 209 if (cproto == fp->proto) { 210 if ((fp->opt.srcop == OP_NONE || 211 PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) 212 && 213 (fp->opt.dstop == OP_NONE || 214 PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) 215 && 216 (fp->opt.estab == 0 || estab)) { 217 return (fp->action); 218 } 219 } 220 } else { 221 /* Address is mached. Make a decision. */ 222 LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action); 223 return (fp->action); 224 } 225 } 226 } 227 fp++; 228 } 229 return (A_DENY); /* No rule is mached. Deny this packet */ 230 } 231 return (A_PERMIT); /* No rule is given. Permit this packet */ 232} 233 234static void 235IcmpError(struct ip * pip, int code) 236{ 237#ifdef notdef 238 struct mbuf *bp; 239 240 if (pip->ip_p != IPPROTO_ICMP) { 241 bp = mballoc(cnt, MB_IPIN); 242 memcpy(MBUF_CTOP(bp), ptr, cnt); 243 SendPppFrame(bp); 244 RestartIdleTimer(); 245 ipOutOctets += cnt; 246 } 247#endif 248} 249 250/* 251 * For debugging aid. 252 */ 253int 254PacketCheck(char *cp, int nb, int direction) 255{ 256 struct ip *pip; 257 struct tcphdr *th; 258 struct udphdr *uh; 259 struct icmp *icmph; 260 char *ptop; 261 int mask, len, n; 262 int pri = PRI_NORMAL; 263 int logit, loglen; 264 static char logbuf[200]; 265 266 logit = LogIsKept(LogTCPIP); 267 loglen = 0; 268 269 pip = (struct ip *) cp; 270 271 if (logit && loglen < sizeof logbuf) { 272 snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", 273 Direction[direction]); 274 loglen += strlen(logbuf + loglen); 275 } 276 ptop = (cp + (pip->ip_hl << 2)); 277 278 switch (pip->ip_p) { 279 case IPPROTO_ICMP: 280 if (logit && loglen < sizeof logbuf) { 281 icmph = (struct icmp *) ptop; 282 snprintf(logbuf + loglen, sizeof logbuf - loglen, 283 "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 284 loglen += strlen(logbuf + loglen); 285 snprintf(logbuf + loglen, sizeof logbuf - loglen, 286 "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); 287 loglen += strlen(logbuf + loglen); 288 } 289 break; 290 case IPPROTO_UDP: 291 if (logit && loglen < sizeof logbuf) { 292 uh = (struct udphdr *) ptop; 293 snprintf(logbuf + loglen, sizeof logbuf - loglen, 294 "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 295 loglen += strlen(logbuf + loglen); 296 snprintf(logbuf + loglen, sizeof logbuf - loglen, 297 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 298 loglen += strlen(logbuf + loglen); 299 } 300 break; 301 case IPPROTO_TCP: 302 th = (struct tcphdr *) ptop; 303 if (pip->ip_tos == IPTOS_LOWDELAY) 304 pri = PRI_FAST; 305 else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 306 if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) 307 pri = PRI_FAST; 308 } 309 if (logit && loglen < sizeof logbuf) { 310 len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 311 snprintf(logbuf + loglen, sizeof logbuf - loglen, 312 "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 313 loglen += strlen(logbuf + loglen); 314 snprintf(logbuf + loglen, sizeof logbuf - loglen, 315 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 316 loglen += strlen(logbuf + loglen); 317 n = 0; 318 for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 319 if (th->th_flags & mask) { 320 snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 321 loglen += strlen(logbuf + loglen); 322 } 323 n++; 324 } 325 snprintf(logbuf + loglen, sizeof logbuf - loglen, 326 " seq:%x ack:%x (%d/%d)", 327 ntohl(th->th_seq), ntohl(th->th_ack), len, nb); 328 loglen += strlen(logbuf + loglen); 329 if ((th->th_flags & TH_SYN) && nb > 40) { 330 u_short *sp; 331 332 ptop += 20; 333 sp = (u_short *) ptop; 334 if (ntohs(sp[0]) == 0x0204) { 335 snprintf(logbuf + loglen, sizeof logbuf - loglen, 336 " MSS = %d", ntohs(sp[1])); 337 loglen += strlen(logbuf + loglen); 338 } 339 } 340 } 341 break; 342 } 343 344 if (logit) 345 LogPrintf(LogTCPIP, "%s\n", logbuf); 346 347 if ((FilterCheck(pip, direction) & A_DENY)) { 348 LogPrintf(LogDEBUG, "blocked.\n"); 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 ipKeepAlive = 0; 355 } else { 356 ipKeepAlive = 1; 357 } 358 return (pri); 359 } 360} 361 362void 363IpInput(struct mbuf * bp) 364{ /* IN: Pointer to IP pakcet */ 365 u_char *cp; 366 struct mbuf *wp; 367 int nb, nw; 368 u_char tunbuff[MAX_MRU]; 369 370 cp = tunbuff; 371 nb = 0; 372 for (wp = bp; wp; wp = wp->next) { /* Copy to contiguous region */ 373 memcpy(cp, MBUF_CTOP(wp), wp->cnt); 374 cp += wp->cnt; 375 nb += wp->cnt; 376 } 377 378 if (mode & MODE_ALIAS) { 379 int iresult; 380 char *fptr; 381 382 iresult = VarPacketAliasIn(tunbuff, sizeof tunbuff); 383 nb = ntohs(((struct ip *) tunbuff)->ip_len); 384 385 if (nb > MAX_MRU) { 386 LogPrintf(LogERROR, "IpInput: Problem with IP header length\n"); 387 pfree(bp); 388 return; 389 } 390 if (iresult == PKT_ALIAS_OK 391 || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 392 if (PacketCheck(tunbuff, nb, FL_IN) < 0) { 393 pfree(bp); 394 return; 395 } 396 ipInOctets += nb; 397 398 nb = ntohs(((struct ip *) tunbuff)->ip_len); 399 nw = write(tun_out, tunbuff, nb); 400 if (nw != nb) 401 if (nw == -1) 402 LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 403 strerror(errno)); 404 else 405 LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 406 407 if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 408 while ((fptr = VarPacketAliasGetFragment(tunbuff)) != NULL) { 409 VarPacketAliasFragmentIn(tunbuff, fptr); 410 nb = ntohs(((struct ip *) fptr)->ip_len); 411 nw = write(tun_out, fptr, nb); 412 if (nw != nb) 413 if (nw == -1) 414 LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 415 strerror(errno)); 416 else 417 LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 418 free(fptr); 419 } 420 } 421 } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) { 422 nb = ntohs(((struct ip *) tunbuff)->ip_len); 423 fptr = malloc(nb); 424 if (fptr == NULL) 425 LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n"); 426 else { 427 memcpy(fptr, tunbuff, nb); 428 VarPacketAliasSaveFragment(fptr); 429 } 430 } 431 } else { /* no aliasing */ 432 if (PacketCheck(tunbuff, nb, FL_IN) < 0) { 433 pfree(bp); 434 return; 435 } 436 ipInOctets += nb; 437 nw = write(tun_out, tunbuff, nb); 438 if (nw != nb) 439 if (nw == -1) 440 LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno)); 441 else 442 LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 443 } 444 pfree(bp); 445 446 RestartIdleTimer(); 447} 448 449static struct mqueue IpOutputQueues[PRI_FAST + 1]; 450 451void 452IpEnqueue(int pri, char *ptr, int count) 453{ 454 struct mbuf *bp; 455 456 bp = mballoc(count, MB_IPQ); 457 memcpy(MBUF_CTOP(bp), ptr, count); 458 Enqueue(&IpOutputQueues[pri], bp); 459} 460 461#if 0 462int 463IsIpEnqueued() 464{ 465 struct mqueue *queue; 466 int exist = 0; 467 468 for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 469 if (queue->qlen > 0) { 470 exist = 1; 471 break; 472 } 473 } 474 return (exist); 475} 476#endif 477 478void 479IpStartOutput() 480{ 481 struct mqueue *queue; 482 struct mbuf *bp; 483 int cnt; 484 485 if (IpcpFsm.state != ST_OPENED) 486 return; 487 for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 488 if (queue->top) { 489 bp = Dequeue(queue); 490 if (bp) { 491 cnt = plength(bp); 492 SendPppFrame(bp); 493 RestartIdleTimer(); 494 ipOutOctets += cnt; 495 break; 496 } 497 } 498 } 499} 500