ip.c revision 6059
1120304Swpaul/*
2119898Swpaul *		PPP IP Protocol Interface
3119898Swpaul *
4119898Swpaul *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5119898Swpaul *
6119898Swpaul *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7119898Swpaul *
8119898Swpaul * Redistribution and use in source and binary forms are permitted
9119898Swpaul * provided that the above copyright notice and this paragraph are
10119898Swpaul * duplicated in all such forms and that any documentation,
11119898Swpaul * advertising materials, and other materials related to such
12119898Swpaul * distribution and use acknowledge that the software was developed
13119898Swpaul * by the Internet Initiative Japan.  The name of the
14119898Swpaul * IIJ may not be used to endorse or promote products derived
15119898Swpaul * from this software without specific prior written permission.
16119898Swpaul * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17119898Swpaul * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18119898Swpaul * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19119898Swpaul *
20119898Swpaul * $Id:$
21119898Swpaul *
22119898Swpaul *	TODO:
23119898Swpaul *		o Return ICMP message for filterd packet
24119898Swpaul *		  and optionaly record it into log.
25119898Swpaul */
26119898Swpaul#include "fsm.h"
27119898Swpaul#include "lcpproto.h"
28119898Swpaul#include "hdlc.h"
29119898Swpaul#include <netinet/in_systm.h>
30119898Swpaul#include <netinet/ip.h>
31119898Swpaul#include <netinet/ip_icmp.h>
32119898Swpaul#include <netinet/udp.h>
33217914Syongari#include <netinet/tcp.h>
34119898Swpaul#include "vars.h"
35119898Swpaul#include "filter.h"
36119898Swpaul
37119898Swpaulextern void SendPppFlame();
38214432Syongariextern int PacketCheck();
39119898Swpaulextern void LcpClose();
40151046Strhodes
41151046Strhodesstatic struct pppTimer IdleTimer;
42148220Strhodes
43148145Strhodesstatic void IdleTimeout()
44119898Swpaul{
45119898Swpaul  LogPrintf(LOG_PHASE, "Idle timer expired.\n");
46148145Strhodes  LcpClose();
47148145Strhodes}
48151046Strhodes
49151046Strhodes/*
50148145Strhodes *  Start Idle timer. If timeout is reached, we call LcpClose() to
51148145Strhodes *  close LCP and link.
52148145Strhodes */
53148145Strhodesvoid
54119898SwpaulStartIdleTimer()
55119898Swpaul{
56119898Swpaul  if (!(mode & MODE_DEDICATED)) {
57119898Swpaul    StopTimer(&IdleTimer);
58214432Syongari    IdleTimer.func = IdleTimeout;
59159962Swpaul    IdleTimer.load = VarIdleTimeout * SECTICKS;
60119898Swpaul    IdleTimer.state = TIMER_STOPPED;
61214432Syongari    StartTimer(&IdleTimer);
62159962Swpaul  }
63214432Syongari}
64214432Syongari
65119898Swpaulvoid
66119898SwpaulStopIdleTimer()
67119898Swpaul{
68119898Swpaul  StopTimer(&IdleTimer);
69131530Sru}
70131530Sru
71119898Swpaul/*
72119898Swpaul *  If any IP layer traffic is detected, refresh IdleTimer.
73119898Swpaul */
74119898Swpaulstatic void
75214432SyongariRestartIdleTimer()
76214432Syongari{
77131530Sru  if (!(mode & MODE_DEDICATED)) {
78131530Sru    StopTimer(&IdleTimer);
79131530Sru    StartTimer(&IdleTimer);
80119898Swpaul    ipIdleSecs = 0;
81119898Swpaul  }
82119898Swpaul}
83119898Swpaul
84135899Sjmgstatic u_short interactive_ports[8] = {
85119898Swpaul  0, 513, 0, 0, 0, 21, 0, 23,
86119898Swpaul};
87119898Swpaul
88119898Swpaul#define	INTERACTIVE(p)	(interactive_ports[(p) & 7] == (p))
89119898Swpaul
90119898Swpaulstatic char *TcpFlags[] = {
91119898Swpaul  "FIN", "SYN", "RST", "PSH", "ACK", "URG",
92131801Sru};
93119898Swpaul
94119898Swpaulstatic char *Direction[] = { "INP", "OUT", "OUT" };
95119898Swpaulstatic struct filterent *Filters[] = { ifilters, ofilters, dfilters };
96119898Swpaul
97119898Swpaulstatic int
98119898SwpaulPortMatch(op, pport, rport)
99119898Swpaulint op;
100119898Swpaulu_short pport, rport;
101119898Swpaul{
102131801Sru  switch (op) {
103119898Swpaul  case OP_EQ:
104119898Swpaul    return(pport == rport);
105119898Swpaul  case OP_GT:
106119898Swpaul    return(pport > rport);
107119898Swpaul  case OP_LT:
108119898Swpaul    return(pport < rport);
109131801Sru  default:
110119898Swpaul    return(0);
111119898Swpaul  }
112131801Sru}
113119898Swpaul
114119898Swpaul/*
115119898Swpaul *  Check a packet against with defined filters
116119898Swpaul */
117119898Swpaulstatic int
118119898SwpaulFilterCheck(pip, direction)
119119898Swpaulstruct ip *pip;
120119898Swpaulint direction;
121119898Swpaul{
122119898Swpaul  struct filterent *fp = Filters[direction];
123119898Swpaul  int gotinfo, cproto, estab, n;
124131801Sru  struct tcphdr *th;
125119898Swpaul  struct udphdr *uh;
126119898Swpaul  struct icmp *ih;
127119898Swpaul  char *ptop;
128119898Swpaul  u_short sport, dport;
129119898Swpaul
130119898Swpaul  if (fp->action) {
131119898Swpaul    cproto = gotinfo = estab = 0;
132119898Swpaul    sport = dport = 0;
133119898Swpaul    for (n = 0; n < MAXFILTERS; n++) {
134119898Swpaul      if (fp->action) {
135131801Sru#ifdef DEBUG
136119898Swpaullogprintf("rule = %d\n", n);
137119898Swpaul#endif
138119898Swpaul	if ((pip->ip_src.s_addr & fp->smask.s_addr) == fp->saddr.s_addr
139119898Swpaul	    && (pip->ip_dst.s_addr & fp->dmask.s_addr) == fp->daddr.s_addr) {
140119898Swpaul	  if (fp->proto) {
141119898Swpaul	    if (!gotinfo) {
142119898Swpaul	      ptop = (char *)pip + (pip->ip_hl << 2);
143119898Swpaul
144134778Sbrueffer	      switch (pip->ip_p) {
145134778Sbrueffer	      case IPPROTO_ICMP:
146134778Sbrueffer		cproto = P_ICMP; ih = (struct icmp *)ptop;
147214432Syongari		sport = ih->icmp_type; estab = 1;
148214432Syongari		break;
149134778Sbrueffer	      case IPPROTO_UDP:
150134778Sbrueffer		cproto = P_UDP; uh = (struct udphdr *)ptop;
151134778Sbrueffer		sport = ntohs(uh->uh_sport); dport = ntohs(uh->uh_dport);
152134778Sbrueffer		estab = 1;
153134778Sbrueffer		break;
154134778Sbrueffer	      case IPPROTO_TCP:
155134778Sbrueffer		cproto = P_TCP; th = (struct tcphdr *)ptop;
156134778Sbrueffer		sport = ntohs(th->th_sport); dport = ntohs(th->th_dport);
157134778Sbrueffer		estab = (th->th_flags & TH_ACK);
158148732Stobez		break;
159148732Stobez	      default:
160134778Sbrueffer		return(A_DENY);	/* We'll block unknown type of packet */
161134778Sbrueffer	      }
162137828Sbrueffer	      gotinfo = 1;
163137828Sbrueffer#ifdef DEBUG
164154362Sbzlogprintf("dir = %d, proto = %d, srcop = %d, dstop = %d, estab = %d\n",
165154362Sbzdirection, cproto, fp->opt.srcop, fp->opt.dstop, estab);
166134778Sbruefferif (estab == 0)
167134778Sbruefferlogprintf("flag = %02x, sport = %d, dport = %d\n", th->th_flags, sport, dport);
168164532Syongari#endif
169164532Syongari	    }
170134778Sbrueffer#ifdef DEBUG
171134778Sbrueffer	    logprintf("check0: rule = %d, proto = %d, sport = %d, dport = %d\n",
172188382Syongari		      n, cproto, sport, dport);
173188382Syongari	    logprintf("check0: action = %d\n", fp->action);
174188382Syongari#endif
175188382Syongari	    if (cproto == fp->proto) {
176188382Syongari	      if ((fp->opt.srcop == OP_NONE ||
177188382Syongari		  PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
178217914Syongari	       &&
179217914Syongari		  (fp->opt.dstop == OP_NONE ||
180217914Syongari		  PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
181217914Syongari	       &&
182217914Syongari		  (fp->opt.estab == 0 || estab)) {
183217914Syongari		return(fp->action);
184188382Syongari	      }
185188382Syongari	    }
186188382Syongari	  } else {
187217914Syongari	    /* Address is mached. Make a decision. */
188217914Syongari#ifdef DEBUG
189217914Syongari	    logprintf("check1: action = %d\n", fp->action);
190216131Syongari#endif
191216131Syongari	    return(fp->action);
192216131Syongari	  }
193216131Syongari	}
194216131Syongari      }
195188382Syongari      fp++;
196217914Syongari    }
197217914Syongaridrop:
198217914Syongari    return(A_DENY);	/* No rule is mached. Deny this packet */
199217914Syongari  }
200217914Syongari  return(A_PERMIT);	/* No rule is given. Permit this packet */
201217914Syongari}
202217914Syongari
203217914Syongaristatic void
204217914SyongariIcmpError(pip, code)
205217914Syongaristruct ip *pip;
206217914Syongariint code;
207217914Syongari{
208217914Syongari#ifdef notdef
209217914Syongari  struct mbuf *bp;
210217914Syongari
211119898Swpaul  if (pip->ip_p != IPPROTO_ICMP) {
212119898Swpaul    bp = mballoc(cnt, MB_IPIN);
213119898Swpaul    bcopy(ptr, MBUF_CTOP(bp), cnt);
214119898Swpaul    SendPppFlame(PRI_URGENT, bp);
215119898Swpaul    RestartIdleTimer();
216119898Swpaul    ipOutOctets += cnt;
217119898Swpaul  }
218119898Swpaul#endif
219119898Swpaul}
220119898Swpaul
221119898Swpaul/*
222119898Swpaul *  For debugging aid.
223119898Swpaul */
224119898Swpaulint
225119898SwpaulPacketCheck(cp, nb, direction)
226119898Swpaulchar *cp;
227119898Swpaulint nb;
228119898Swpaulint direction;
229119898Swpaul{
230119898Swpaul  struct ip *pip;
231119898Swpaul  struct tcphdr *th;
232119898Swpaul  struct udphdr *uh;
233119898Swpaul  struct icmp *icmph;
234166346Sbrueffer  char *ptop;
235119898Swpaul  int mask, len, n;
236124302Sbrueffer  int logit;
237119898Swpaul  int pri = PRI_NORMAL;
238119898Swpaul
239138068Sbrueffer  logit = (loglevel & (1 << LOG_TCPIP));
240217464Smarius
241119898Swpaul  pip = (struct ip *)cp;
242119898Swpaul
243119898Swpaul  if (logit) logprintf("%s  ", Direction[direction]);
244119898Swpaul
245202386Sru  ptop = (cp + (pip->ip_hl << 2));
246119898Swpaul
247119898Swpaul  switch (pip->ip_p) {
248119898Swpaul  case IPPROTO_ICMP:
249119898Swpaul    if (logit) {
250119898Swpaul      icmph = (struct icmp *)ptop;
251119898Swpaul      logprintf("ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
252119898Swpaul      logprintf("%s:%d\n", inet_ntoa(pip->ip_dst), icmph->icmp_type);
253119898Swpaul    }
254119898Swpaul    break;
255119898Swpaul  case IPPROTO_UDP:
256119898Swpaul    if (logit) {
257119898Swpaul      uh = (struct udphdr *)ptop;
258119898Swpaul      logprintf("UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
259119898Swpaul      logprintf("%s:%d\n", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
260131530Sru    }
261131530Sru    break;
262119898Swpaul  case IPPROTO_TCP:
263131530Sru    th = (struct tcphdr *)ptop;
264131530Sru    if (pip->ip_tos == IPTOS_LOWDELAY)
265119898Swpaul      pri = PRI_FAST;
266119898Swpaul    else if (pip->ip_off == 0) {
267119898Swpaul      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
268119898Swpaul	 pri = PRI_FAST;
269131530Sru    }
270131530Sru
271119898Swpaul    if (logit) {
272119898Swpaul      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
273119898Swpaul      logprintf("TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
274131530Sru      logprintf("%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
275131530Sru      n = 0;
276119898Swpaul      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
277131530Sru	if (th->th_flags & mask)
278131530Sru	  logprintf(" %s", TcpFlags[n]);
279131530Sru	n++;
280131530Sru      }
281211936Sbrucec      logprintf("  seq:%x  ack:%x (%d/%d)\n",
282119898Swpaul	ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
283119898Swpaul      if ((th->th_flags & TH_SYN) && nb > 40) {
284119898Swpaul        u_short *sp;
285119898Swpaul
286	ptop += 20;
287	sp = (u_short *)ptop;
288	if (ntohs(sp[0]) == 0x0204)
289	  logprintf(" MSS = %d\n", ntohs(sp[1]));
290      }
291    }
292    break;
293  }
294  pri = FilterCheck(pip, direction);
295  if (pri & A_DENY) {
296#ifdef DEBUG
297    logprintf("blocked.\n");
298#endif
299    if (direction == 0) IcmpError(pip, pri);
300    return(-1);
301  } else {
302    return(pri);
303  }
304}
305
306void
307IpInput(bp)
308struct mbuf *bp;		/* IN: Pointer to IP pakcet */
309{
310  u_char *cp;
311  struct mbuf *wp;
312  int nb, nw;
313  u_char tunbuff[MAX_MRU];
314
315  cp = tunbuff;
316  nb = 0;
317  for (wp = bp; wp; wp = wp->next) {		/* Copy to continuois region */
318    bcopy(MBUF_CTOP(wp), cp, wp->cnt);
319    cp += wp->cnt;
320    nb += wp->cnt;
321  }
322
323  if (PacketCheck(tunbuff, nb, 0) < 0) {
324    pfree(bp);
325    return;
326  }
327
328  ipInOctets += nb;
329  /*
330   *  Pass it to tunnel device
331   */
332  nw = write(tun_out, tunbuff, nb);
333  if (nw != nb)
334    fprintf(stderr, "wrote %d, got %d\r\n");
335  pfree(bp);
336
337  RestartIdleTimer();
338}
339
340void
341IpOutput(ptr, cnt)
342u_char *ptr;			/* IN: Pointer to IP packet */
343int cnt;			/* IN: Length of packet */
344{
345  struct mbuf *bp;
346  int pri;
347
348  if (IpcpFsm.state != ST_OPENED)
349    return;
350
351  pri = PacketCheck(ptr, cnt, 1);
352  if (pri >= 0) {
353    bp = mballoc(cnt, MB_IPIN);
354    bcopy(ptr, MBUF_CTOP(bp), cnt);
355    SendPppFlame(pri, bp);
356    RestartIdleTimer();
357    ipOutOctets += cnt;
358  }
359}
360
361static struct mqueue IpOutputQueues[PRI_URGENT+1];
362
363void
364IpEnqueue(pri, ptr, count)
365int pri;
366char *ptr;
367int count;
368{
369  struct mbuf *bp;
370
371  bp = mballoc(count, MB_IPQ);
372  bcopy(ptr, MBUF_CTOP(bp), count);
373  Enqueue(&IpOutputQueues[pri], bp);
374}
375
376void
377IpStartOutput()
378{
379  struct mqueue *queue;
380  struct mbuf *bp;
381  int pri, cnt;
382
383  if (IpcpFsm.state != ST_OPENED)
384    return;
385  pri = PRI_URGENT;
386  for (queue = &IpOutputQueues[PRI_URGENT]; queue >= IpOutputQueues; queue--) {
387    if (queue->top) {
388      bp = Dequeue(queue);
389      if (bp) {
390	cnt = plength(bp);
391	SendPppFlame(pri, bp);
392	RestartIdleTimer();
393	ipOutOctets += cnt;
394       }
395    }
396    pri--;
397  }
398}
399