xref: /freebsd/usr.sbin/ppp/ip.c (revision 17ee9d00bc1ae1e598c38f25826f861e4bc6c3ce)
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:$
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 "vars.h"
35 #include "filter.h"
36 
37 extern void SendPppFlame();
38 extern int PacketCheck();
39 extern void LcpClose();
40 
41 static struct pppTimer IdleTimer;
42 
43 static void IdleTimeout()
44 {
45   LogPrintf(LOG_PHASE, "Idle timer expired.\n");
46   LcpClose();
47 }
48 
49 /*
50  *  Start Idle timer. If timeout is reached, we call LcpClose() to
51  *  close LCP and link.
52  */
53 void
54 StartIdleTimer()
55 {
56   if (!(mode & MODE_DEDICATED)) {
57     StopTimer(&IdleTimer);
58     IdleTimer.func = IdleTimeout;
59     IdleTimer.load = VarIdleTimeout * SECTICKS;
60     IdleTimer.state = TIMER_STOPPED;
61     StartTimer(&IdleTimer);
62   }
63 }
64 
65 void
66 StopIdleTimer()
67 {
68   StopTimer(&IdleTimer);
69 }
70 
71 /*
72  *  If any IP layer traffic is detected, refresh IdleTimer.
73  */
74 static void
75 RestartIdleTimer()
76 {
77   if (!(mode & MODE_DEDICATED)) {
78     StopTimer(&IdleTimer);
79     StartTimer(&IdleTimer);
80     ipIdleSecs = 0;
81   }
82 }
83 
84 static u_short interactive_ports[8] = {
85   0, 513, 0, 0, 0, 21, 0, 23,
86 };
87 
88 #define	INTERACTIVE(p)	(interactive_ports[(p) & 7] == (p))
89 
90 static char *TcpFlags[] = {
91   "FIN", "SYN", "RST", "PSH", "ACK", "URG",
92 };
93 
94 static char *Direction[] = { "INP", "OUT", "OUT" };
95 static struct filterent *Filters[] = { ifilters, ofilters, dfilters };
96 
97 static int
98 PortMatch(op, pport, rport)
99 int op;
100 u_short pport, rport;
101 {
102   switch (op) {
103   case OP_EQ:
104     return(pport == rport);
105   case OP_GT:
106     return(pport > rport);
107   case OP_LT:
108     return(pport < rport);
109   default:
110     return(0);
111   }
112 }
113 
114 /*
115  *  Check a packet against with defined filters
116  */
117 static int
118 FilterCheck(pip, direction)
119 struct ip *pip;
120 int direction;
121 {
122   struct filterent *fp = Filters[direction];
123   int gotinfo, cproto, estab, n;
124   struct tcphdr *th;
125   struct udphdr *uh;
126   struct icmp *ih;
127   char *ptop;
128   u_short sport, dport;
129 
130   if (fp->action) {
131     cproto = gotinfo = estab = 0;
132     sport = dport = 0;
133     for (n = 0; n < MAXFILTERS; n++) {
134       if (fp->action) {
135 #ifdef DEBUG
136 logprintf("rule = %d\n", n);
137 #endif
138 	if ((pip->ip_src.s_addr & fp->smask.s_addr) == fp->saddr.s_addr
139 	    && (pip->ip_dst.s_addr & fp->dmask.s_addr) == fp->daddr.s_addr) {
140 	  if (fp->proto) {
141 	    if (!gotinfo) {
142 	      ptop = (char *)pip + (pip->ip_hl << 2);
143 
144 	      switch (pip->ip_p) {
145 	      case IPPROTO_ICMP:
146 		cproto = P_ICMP; ih = (struct icmp *)ptop;
147 		sport = ih->icmp_type; estab = 1;
148 		break;
149 	      case IPPROTO_UDP:
150 		cproto = P_UDP; uh = (struct udphdr *)ptop;
151 		sport = ntohs(uh->uh_sport); dport = ntohs(uh->uh_dport);
152 		estab = 1;
153 		break;
154 	      case IPPROTO_TCP:
155 		cproto = P_TCP; th = (struct tcphdr *)ptop;
156 		sport = ntohs(th->th_sport); dport = ntohs(th->th_dport);
157 		estab = (th->th_flags & TH_ACK);
158 		break;
159 	      default:
160 		return(A_DENY);	/* We'll block unknown type of packet */
161 	      }
162 	      gotinfo = 1;
163 #ifdef DEBUG
164 logprintf("dir = %d, proto = %d, srcop = %d, dstop = %d, estab = %d\n",
165 direction, cproto, fp->opt.srcop, fp->opt.dstop, estab);
166 if (estab == 0)
167 logprintf("flag = %02x, sport = %d, dport = %d\n", th->th_flags, sport, dport);
168 #endif
169 	    }
170 #ifdef DEBUG
171 	    logprintf("check0: rule = %d, proto = %d, sport = %d, dport = %d\n",
172 		      n, cproto, sport, dport);
173 	    logprintf("check0: action = %d\n", fp->action);
174 #endif
175 	    if (cproto == fp->proto) {
176 	      if ((fp->opt.srcop == OP_NONE ||
177 		  PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
178 	       &&
179 		  (fp->opt.dstop == OP_NONE ||
180 		  PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
181 	       &&
182 		  (fp->opt.estab == 0 || estab)) {
183 		return(fp->action);
184 	      }
185 	    }
186 	  } else {
187 	    /* Address is mached. Make a decision. */
188 #ifdef DEBUG
189 	    logprintf("check1: action = %d\n", fp->action);
190 #endif
191 	    return(fp->action);
192 	  }
193 	}
194       }
195       fp++;
196     }
197 drop:
198     return(A_DENY);	/* No rule is mached. Deny this packet */
199   }
200   return(A_PERMIT);	/* No rule is given. Permit this packet */
201 }
202 
203 static void
204 IcmpError(pip, code)
205 struct ip *pip;
206 int code;
207 {
208 #ifdef notdef
209   struct mbuf *bp;
210 
211   if (pip->ip_p != IPPROTO_ICMP) {
212     bp = mballoc(cnt, MB_IPIN);
213     bcopy(ptr, MBUF_CTOP(bp), cnt);
214     SendPppFlame(PRI_URGENT, bp);
215     RestartIdleTimer();
216     ipOutOctets += cnt;
217   }
218 #endif
219 }
220 
221 /*
222  *  For debugging aid.
223  */
224 int
225 PacketCheck(cp, nb, direction)
226 char *cp;
227 int nb;
228 int direction;
229 {
230   struct ip *pip;
231   struct tcphdr *th;
232   struct udphdr *uh;
233   struct icmp *icmph;
234   char *ptop;
235   int mask, len, n;
236   int logit;
237   int pri = PRI_NORMAL;
238 
239   logit = (loglevel & (1 << LOG_TCPIP));
240 
241   pip = (struct ip *)cp;
242 
243   if (logit) logprintf("%s  ", Direction[direction]);
244 
245   ptop = (cp + (pip->ip_hl << 2));
246 
247   switch (pip->ip_p) {
248   case IPPROTO_ICMP:
249     if (logit) {
250       icmph = (struct icmp *)ptop;
251       logprintf("ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
252       logprintf("%s:%d\n", inet_ntoa(pip->ip_dst), icmph->icmp_type);
253     }
254     break;
255   case IPPROTO_UDP:
256     if (logit) {
257       uh = (struct udphdr *)ptop;
258       logprintf("UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
259       logprintf("%s:%d\n", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
260     }
261     break;
262   case IPPROTO_TCP:
263     th = (struct tcphdr *)ptop;
264     if (pip->ip_tos == IPTOS_LOWDELAY)
265       pri = PRI_FAST;
266     else if (pip->ip_off == 0) {
267       if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
268 	 pri = PRI_FAST;
269     }
270 
271     if (logit) {
272       len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
273       logprintf("TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
274       logprintf("%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
275       n = 0;
276       for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
277 	if (th->th_flags & mask)
278 	  logprintf(" %s", TcpFlags[n]);
279 	n++;
280       }
281       logprintf("  seq:%x  ack:%x (%d/%d)\n",
282 	ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
283       if ((th->th_flags & TH_SYN) && nb > 40) {
284         u_short *sp;
285 
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 
306 void
307 IpInput(bp)
308 struct 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 
340 void
341 IpOutput(ptr, cnt)
342 u_char *ptr;			/* IN: Pointer to IP packet */
343 int 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 
361 static struct mqueue IpOutputQueues[PRI_URGENT+1];
362 
363 void
364 IpEnqueue(pri, ptr, count)
365 int pri;
366 char *ptr;
367 int 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 
376 void
377 IpStartOutput()
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