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