ip.c revision 32039
1119026Sume/*
266776Skris *		PPP IP Protocol Interface
355163Sshin *
455163Sshin *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
555163Sshin *
662632Skris *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
755163Sshin *
855163Sshin * Redistribution and use in source and binary forms are permitted
955163Sshin * provided that the above copyright notice and this paragraph are
1055163Sshin * duplicated in all such forms and that any documentation,
1155163Sshin * advertising materials, and other materials related to such
1255163Sshin * distribution and use acknowledge that the software was developed
1355163Sshin * by the Internet Initiative Japan.  The name of the
1455163Sshin * IIJ may not be used to endorse or promote products derived
1555163Sshin * from this software without specific prior written permission.
1655163Sshin * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1755163Sshin * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1862632Skris * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1955163Sshin *
2055163Sshin * $Id: ip.c,v 1.33 1997/12/24 09:29:01 brian Exp $
2155163Sshin *
2255163Sshin *	TODO:
2355163Sshin *		o Return ICMP message for filterd packet
2455163Sshin *		  and optionaly record it into log.
2555163Sshin */
2655163Sshin#include <sys/param.h>
2755163Sshin#include <sys/time.h>
2855163Sshin#include <sys/select.h>
2955163Sshin#include <sys/socket.h>
3055163Sshin#include <netinet/in.h>
3155163Sshin#include <netinet/in_systm.h>
3255163Sshin#include <netinet/ip.h>
3355163Sshin#include <netinet/ip_icmp.h>
34222732Shrs#include <netinet/udp.h>
35222732Shrs#include <netinet/tcp.h>
36222732Shrs#include <arpa/inet.h>
37222732Shrs#include <net/if.h>
38222732Shrs#ifdef __FreeBSD__
39222732Shrs#include <net/if_var.h>
40225520Shrs#endif
41225520Shrs#include <net/if_tun.h>
42222732Shrs
43222732Shrs#ifndef NOALIAS
44222732Shrs#include <alias.h>
45222732Shrs#endif
46253970Shrs#include <errno.h>
47222732Shrs#include <stdio.h>
48222732Shrs#include <stdlib.h>
49222732Shrs#include <string.h>
50222732Shrs#include <termios.h>
51222861Shrs#include <unistd.h>
52222861Shrs
53222861Shrs#include "command.h"
54222861Shrs#include "mbuf.h"
55222861Shrs#include "log.h"
56222861Shrs#include "defs.h"
57222861Shrs#include "timer.h"
58222861Shrs#include "fsm.h"
59222861Shrs#include "lcpproto.h"
60222861Shrs#include "hdlc.h"
6155163Sshin#include "loadalias.h"
62222732Shrs#include "vars.h"
6355163Sshin#include "filter.h"
6455163Sshin#include "os.h"
65225520Shrs#include "ipcp.h"
66119026Sume#include "vjcomp.h"
6755163Sshin#include "lcp.h"
68118664Sume#include "modem.h"
6955163Sshin#include "tun.h"
7055163Sshin#include "ip.h"
71118661Sume
72118661Sumestatic struct pppTimer IdleTimer;
7355163Sshin
7455163Sshinstatic void
7555163SshinIdleTimeout(void *v)
76253970Shrs{
77253970Shrs  LogPrintf(LogPHASE, "Idle timer expired.\n");
7862632Skris  reconnect(RECON_FALSE);
79222861Shrs  LcpClose();
80222861Shrs}
81222861Shrs
82222861Shrs/*
8355163Sshin *  Start Idle timer. If timeout is reached, we call LcpClose() to
8455163Sshin *  close LCP and link.
85222861Shrs */
8655163Sshinvoid
8755163SshinStartIdleTimer()
8855163Sshin{
8955163Sshin  if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) {
9055163Sshin    StopTimer(&IdleTimer);
9155163Sshin    IdleTimer.func = IdleTimeout;
9262632Skris    IdleTimer.load = VarIdleTimeout * SECTICKS;
9362632Skris    IdleTimer.state = TIMER_STOPPED;
9462632Skris    StartTimer(&IdleTimer);
9562632Skris  }
9662632Skris}
9755163Sshin
98222732Shrsvoid
99222732ShrsUpdateIdleTimer()
100222732Shrs{
101225520Shrs  if (OsLinkIsUp())
102222732Shrs    StartIdleTimer();
103222732Shrs}
104222732Shrs
105222732Shrsvoid
106222732ShrsStopIdleTimer()
107222732Shrs{
108222732Shrs  StopTimer(&IdleTimer);
109222732Shrs}
110222732Shrs
111222732Shrs/*
112222732Shrs *  If any IP layer traffic is detected, refresh IdleTimer.
113222732Shrs */
114222732Shrsstatic void
115222732ShrsRestartIdleTimer(void)
116222732Shrs{
117222732Shrs  if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) {
118222732Shrs    StartTimer(&IdleTimer);
119222732Shrs    ipIdleSecs = 0;
120222732Shrs  }
121222732Shrs}
122222732Shrs
123222732Shrsstatic const u_short interactive_ports[32] = {
124222732Shrs  544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
125222732Shrs  0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
126222732Shrs};
127253970Shrs
128253970Shrs#define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
129253970Shrs
130253970Shrsstatic const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
131253970Shrs
132253970Shrsstatic const char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"};
133253970Shrsstatic struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters};
134253970Shrs
135253970Shrsstatic int
136253970ShrsPortMatch(int op, u_short pport, u_short rport)
137253970Shrs{
138253970Shrs  switch (op) {
139253970Shrs    case OP_EQ:
140253970Shrs    return (pport == rport);
141253970Shrs  case OP_GT:
142253970Shrs    return (pport > rport);
143253970Shrs  case OP_LT:
144253970Shrs    return (pport < rport);
145253970Shrs  default:
146253970Shrs    return (0);
147253970Shrs  }
148253970Shrs}
149253970Shrs
15055163Sshin/*
151253970Shrs *  Check a packet against with defined filters
15255163Sshin */
153119026Sumestatic int
154197141ShrsFilterCheck(struct ip * pip, int direction)
155225520Shrs{
156222732Shrs  struct filterent *fp = Filters[direction];
157222732Shrs  int gotinfo, cproto, estab, n;
158173412Skevlo  struct tcphdr *th;
159173412Skevlo  struct udphdr *uh;
160173412Skevlo  struct icmp *ih;
161222861Shrs  char *ptop;
162173412Skevlo  u_short sport, dport;
163173412Skevlo
16466776Skris  if (fp->action) {
165173412Skevlo    cproto = gotinfo = estab = 0;
166222732Shrs    sport = dport = 0;
16755163Sshin    for (n = 0; n < MAXFILTERS; n++) {
16855163Sshin      if (fp->action) {
169173412Skevlo	/* permit fragments on in and out filter */
170173412Skevlo	if ((direction == FL_IN || direction == FL_OUT) &&
171173412Skevlo	    (ntohs(pip->ip_off) & IP_OFFMASK) != 0) {
172173412Skevlo	  return (A_PERMIT);
173173412Skevlo	}
174173412Skevlo	LogPrintf(LogDEBUG, "rule = %d\n", n);
175173412Skevlo	if ((pip->ip_src.s_addr & fp->smask.s_addr) ==
176173412Skevlo	    (fp->saddr.s_addr & fp->smask.s_addr) &&
17755163Sshin	    (pip->ip_dst.s_addr & fp->dmask.s_addr) ==
17855163Sshin	    (fp->daddr.s_addr & fp->dmask.s_addr)) {
179254462Shrs	  if (fp->proto) {
180173412Skevlo	    if (!gotinfo) {
181173412Skevlo	      ptop = (char *) pip + (pip->ip_hl << 2);
182173412Skevlo
18355163Sshin	      switch (pip->ip_p) {
18455163Sshin	      case IPPROTO_ICMP:
185173412Skevlo		cproto = P_ICMP;
186173412Skevlo		ih = (struct icmp *) ptop;
18755163Sshin		sport = ih->icmp_type;
18855163Sshin		estab = 1;
189204407Suqs		break;
190253970Shrs	      case IPPROTO_UDP:
19178064Sume		cproto = P_UDP;
19278064Sume		uh = (struct udphdr *) ptop;
193173412Skevlo		sport = ntohs(uh->uh_sport);
194173412Skevlo		dport = ntohs(uh->uh_dport);
195		estab = 1;
196		break;
197	      case IPPROTO_TCP:
198		cproto = P_TCP;
199		th = (struct tcphdr *) ptop;
200		sport = ntohs(th->th_sport);
201		dport = ntohs(th->th_dport);
202		estab = (th->th_flags & TH_ACK);
203		if (estab == 0)
204		  LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n",
205			    th->th_flags, sport, dport);
206		break;
207	      default:
208		return (A_DENY);/* We'll block unknown type of packet */
209	      }
210	      gotinfo = 1;
211	      LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d,"
212			" dstop = %d, estab = %d\n", direction, cproto,
213			fp->opt.srcop, fp->opt.dstop, estab);
214	    }
215	    LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d,"
216		      " dport = %d\n", n, cproto, sport, dport);
217	    LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action);
218
219	    if (cproto == fp->proto) {
220	      if ((fp->opt.srcop == OP_NONE ||
221		   PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
222		  &&
223		  (fp->opt.dstop == OP_NONE ||
224		   PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
225		  &&
226		  (fp->opt.estab == 0 || estab)) {
227		return (fp->action);
228	      }
229	    }
230	  } else {
231	    /* Address is mached. Make a decision. */
232	    LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action);
233	    return (fp->action);
234	  }
235	}
236      }
237      fp++;
238    }
239    return (A_DENY);		/* No rule is mached. Deny this packet */
240  }
241  return (A_PERMIT);		/* No rule is given. Permit this packet */
242}
243
244static void
245IcmpError(struct ip * pip, int code)
246{
247#ifdef notdef
248  struct mbuf *bp;
249
250  if (pip->ip_p != IPPROTO_ICMP) {
251    bp = mballoc(cnt, MB_IPIN);
252    memcpy(MBUF_CTOP(bp), ptr, cnt);
253    SendPppFrame(bp);
254    RestartIdleTimer();
255    IpcpAddOutOctets(cnt);
256  }
257#endif
258}
259
260/*
261 *  For debugging aid.
262 */
263int
264PacketCheck(char *cp, int nb, int direction)
265{
266  struct ip *pip;
267  struct tcphdr *th;
268  struct udphdr *uh;
269  struct icmp *icmph;
270  char *ptop;
271  int mask, len, n;
272  int pri = PRI_NORMAL;
273  int logit, loglen;
274  static char logbuf[200];
275
276  logit = LogIsKept(LogTCPIP) && direction != FL_DIAL;
277  loglen = 0;
278
279  pip = (struct ip *) cp;
280
281  if (logit && loglen < sizeof logbuf) {
282    snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ",
283	     Direction[direction]);
284    loglen += strlen(logbuf + loglen);
285  }
286  ptop = (cp + (pip->ip_hl << 2));
287
288  switch (pip->ip_p) {
289  case IPPROTO_ICMP:
290    if (logit && loglen < sizeof logbuf) {
291      icmph = (struct icmp *) ptop;
292      snprintf(logbuf + loglen, sizeof logbuf - loglen,
293	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
294      loglen += strlen(logbuf + loglen);
295      snprintf(logbuf + loglen, sizeof logbuf - loglen,
296	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
297      loglen += strlen(logbuf + loglen);
298    }
299    break;
300  case IPPROTO_UDP:
301    if (logit && loglen < sizeof logbuf) {
302      uh = (struct udphdr *) ptop;
303      snprintf(logbuf + loglen, sizeof logbuf - loglen,
304	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
305      loglen += strlen(logbuf + loglen);
306      snprintf(logbuf + loglen, sizeof logbuf - loglen,
307	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
308      loglen += strlen(logbuf + loglen);
309    }
310    break;
311  case IPPROTO_TCP:
312    th = (struct tcphdr *) ptop;
313    if (pip->ip_tos == IPTOS_LOWDELAY)
314      pri = PRI_FAST;
315    else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
316      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
317	pri = PRI_FAST;
318    }
319    if (logit && loglen < sizeof logbuf) {
320      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
321      snprintf(logbuf + loglen, sizeof logbuf - loglen,
322	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
323      loglen += strlen(logbuf + loglen);
324      snprintf(logbuf + loglen, sizeof logbuf - loglen,
325	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
326      loglen += strlen(logbuf + loglen);
327      n = 0;
328      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
329	if (th->th_flags & mask) {
330	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
331	  loglen += strlen(logbuf + loglen);
332	}
333	n++;
334      }
335      snprintf(logbuf + loglen, sizeof logbuf - loglen,
336	       "  seq:%x  ack:%x (%d/%d)",
337	       ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
338      loglen += strlen(logbuf + loglen);
339      if ((th->th_flags & TH_SYN) && nb > 40) {
340	u_short *sp;
341
342	ptop += 20;
343	sp = (u_short *) ptop;
344	if (ntohs(sp[0]) == 0x0204) {
345	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
346		   " MSS = %d", ntohs(sp[1]));
347	  loglen += strlen(logbuf + loglen);
348	}
349      }
350    }
351    break;
352  }
353
354  if ((FilterCheck(pip, direction) & A_DENY)) {
355    if (logit)
356      LogPrintf(LogTCPIP, "%s - BLOCKED\n", logbuf);
357    if (direction == 0)
358      IcmpError(pip, pri);
359    return (-1);
360  } else {
361    if (FilterCheck(pip, FL_KEEP) & A_DENY) {	/* Check Keep Alive filter */
362      if (logit)
363        LogPrintf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
364      ipKeepAlive = 0;
365    } else {
366      if (logit)
367        LogPrintf(LogTCPIP, "%s\n", logbuf);
368      ipKeepAlive = 1;
369    }
370    return (pri);
371  }
372}
373
374void
375IpInput(struct mbuf * bp)
376{				/* IN: Pointer to IP pakcet */
377  u_char *cp;
378  struct mbuf *wp;
379  int nb, nw;
380  struct tun_data tun;
381
382  tun_fill_header(tun, AF_INET);
383  cp = tun.data;
384  nb = 0;
385  for (wp = bp; wp; wp = wp->next) {	/* Copy to contiguous region */
386    memcpy(cp, MBUF_CTOP(wp), wp->cnt);
387    cp += wp->cnt;
388    nb += wp->cnt;
389  }
390
391#ifndef NOALIAS
392  if (mode & MODE_ALIAS) {
393    struct tun_data *frag;
394    int iresult;
395    char *fptr;
396
397    iresult = VarPacketAliasIn(tun.data, sizeof tun.data);
398    nb = ntohs(((struct ip *) tun.data)->ip_len);
399
400    if (nb > MAX_MRU) {
401      LogPrintf(LogERROR, "IpInput: Problem with IP header length\n");
402      pfree(bp);
403      return;
404    }
405    if (iresult == PKT_ALIAS_OK
406	|| iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
407      if (PacketCheck(tun.data, nb, FL_IN) < 0) {
408	pfree(bp);
409	return;
410      }
411      IpcpAddInOctets(nb);
412
413      nb = ntohs(((struct ip *) tun.data)->ip_len);
414      nb += sizeof tun - sizeof tun.data;
415      nw = write(tun_out, &tun, 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
423      if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
424	while ((fptr = VarPacketAliasGetFragment(tun.data)) != NULL) {
425	  VarPacketAliasFragmentIn(tun.data, fptr);
426	  nb = ntohs(((struct ip *) fptr)->ip_len);
427          frag = (struct tun_data *)
428	    ((char *)fptr - sizeof tun + sizeof tun.data);
429          nb += sizeof tun - sizeof tun.data;
430	  nw = write(tun_out, frag, nb);
431	  if (nw != nb)
432            if (nw == -1)
433	      LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
434                        strerror(errno));
435            else
436	      LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
437	  free(frag);
438	}
439      }
440    } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
441      nb = ntohs(((struct ip *) tun.data)->ip_len);
442      nb += sizeof tun - sizeof tun.data;
443      frag = (struct tun_data *)malloc(nb);
444      if (frag == NULL)
445	LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n");
446      else {
447        tun_fill_header(*frag, AF_INET);
448	memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data);
449	VarPacketAliasSaveFragment(frag->data);
450      }
451    }
452  } else
453#endif /* #ifndef NOALIAS */
454  {			/* no aliasing */
455    if (PacketCheck(tun.data, nb, FL_IN) < 0) {
456      pfree(bp);
457      return;
458    }
459    IpcpAddInOctets(nb);
460    nb += sizeof tun - sizeof tun.data;
461    nw = write(tun_out, &tun, nb);
462    if (nw != nb)
463      if (nw == -1)
464	LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno));
465      else
466        LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
467  }
468  pfree(bp);
469
470  RestartIdleTimer();
471}
472
473static struct mqueue IpOutputQueues[PRI_FAST + 1];
474
475void
476IpEnqueue(int pri, char *ptr, int count)
477{
478  struct mbuf *bp;
479
480  bp = mballoc(count, MB_IPQ);
481  memcpy(MBUF_CTOP(bp), ptr, count);
482  Enqueue(&IpOutputQueues[pri], bp);
483}
484
485#if 0
486int
487IsIpEnqueued()
488{
489  struct mqueue *queue;
490  int exist = 0;
491
492  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
493    if (queue->qlen > 0) {
494      exist = 1;
495      break;
496    }
497  }
498  return (exist);
499}
500#endif
501
502void
503IpStartOutput()
504{
505  struct mqueue *queue;
506  struct mbuf *bp;
507  int cnt;
508
509  if (IpcpFsm.state != ST_OPENED)
510    return;
511  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
512    if (queue->top) {
513      bp = Dequeue(queue);
514      if (bp) {
515	cnt = plength(bp);
516	SendPppFrame(bp);
517	RestartIdleTimer();
518        IpcpAddOutOctets(cnt);
519	break;
520      }
521    }
522  }
523}
524