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