Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / dist / ipf / netinet / ip_irc_pxy.c
blob1b524d086fb56e9b3de0f168f1324b0a508d5745
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2000-2003 Darren Reed
6 * See the IPFILTER.LICENCE file for details on licencing.
8 * Id: ip_irc_pxy.c,v 2.39.2.9 2008/11/06 21:18:34 darrenr Exp
9 */
11 #include <sys/cdefs.h>
12 __KERNEL_RCSID(1, "$NetBSD$");
14 #define IPF_IRC_PROXY
16 #define IPF_IRCBUFSZ 96 /* This *MUST* be >= 64! */
19 int ippr_irc_init __P((void));
20 void ippr_irc_fini __P((void));
21 int ippr_irc_new __P((fr_info_t *, ap_session_t *, nat_t *));
22 int ippr_irc_out __P((fr_info_t *, ap_session_t *, nat_t *));
23 int ippr_irc_send __P((fr_info_t *, nat_t *));
24 int ippr_irc_complete __P((ircinfo_t *, char *, size_t));
25 u_short ipf_irc_atoi __P((char **));
27 static frentry_t ircnatfr;
29 int irc_proxy_init = 0;
33 * Initialize local structures.
35 int ippr_irc_init()
37 bzero((char *)&ircnatfr, sizeof(ircnatfr));
38 ircnatfr.fr_ref = 1;
39 ircnatfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
40 MUTEX_INIT(&ircnatfr.fr_lock, "IRC proxy rule lock");
41 irc_proxy_init = 1;
43 return 0;
47 void ippr_irc_fini()
49 if (irc_proxy_init == 1) {
50 MUTEX_DESTROY(&ircnatfr.fr_lock);
51 irc_proxy_init = 0;
56 const char *ippr_irc_dcctypes[] = {
57 "CHAT ", /* CHAT chat ipnumber portnumber */
58 "SEND ", /* SEND filename ipnumber portnumber */
59 "MOVE ",
60 "TSEND ",
61 "SCHAT ",
62 NULL,
67 * :A PRIVMSG B :^ADCC CHAT chat 0 0^A\r\n
68 * PRIVMSG B ^ADCC CHAT chat 0 0^A\r\n
72 int ippr_irc_complete(ircp, buf, len)
73 ircinfo_t *ircp;
74 char *buf;
75 size_t len;
77 register char *s, c;
78 register size_t i;
79 u_32_t l;
80 int j, k;
82 ircp->irc_ipnum = 0;
83 ircp->irc_port = 0;
85 if (len < 31)
86 return 0;
87 s = buf;
88 c = *s++;
89 i = len - 1;
91 if ((c != ':') && (c != 'P'))
92 return 0;
94 if (c == ':') {
96 * Loosely check that the source is a nickname of some sort
98 s++;
99 c = *s;
100 ircp->irc_snick = s;
101 if (!ISALPHA(c))
102 return 0;
103 i--;
104 for (c = *s; !ISSPACE(c) && (i > 0); i--)
105 c = *s++;
106 if (i < 31)
107 return 0;
108 if (c != 'P')
109 return 0;
110 } else
111 ircp->irc_snick = NULL;
114 * Check command string
116 if (strncmp(s, "PRIVMSG ", 8))
117 return 0;
118 i -= 8;
119 s += 8;
120 c = *s;
121 ircp->irc_dnick = s;
124 * Loosely check that the destination is a nickname of some sort
126 if (!ISALPHA(c))
127 return 0;
128 for (; !ISSPACE(c) && (i > 0); i--)
129 c = *s++;
130 if (i < 20)
131 return 0;
132 s++,
133 i--;
136 * Look for a ^A to start the DCC
138 c = *s;
139 if (c == ':') {
140 s++;
141 c = *s;
144 if (strncmp(s, "\001DCC ", 4))
145 return 0;
147 i -= 4;
148 s += 4;
151 * Check for a recognised DCC command
153 for (j = 0, k = 0; ippr_irc_dcctypes[j]; j++) {
154 k = MIN(strlen(ippr_irc_dcctypes[j]), i);
155 if (!strncmp(ippr_irc_dcctypes[j], s, k))
156 break;
158 if (!ippr_irc_dcctypes[j])
159 return 0;
161 ircp->irc_type = s;
162 i -= k;
163 s += k;
165 if (i < 11)
166 return 0;
169 * Check for the arg
171 c = *s;
172 if (ISSPACE(c))
173 return 0;
174 ircp->irc_arg = s;
175 for (; (c != ' ') && (c != '\001') && (i > 0); i--)
176 c = *s++;
178 if (c == '\001') /* In reality a ^A can quote another ^A...*/
179 return 0;
181 if (i < 5)
182 return 0;
184 s++;
185 i--;
186 c = *s;
187 if (!ISDIGIT(c))
188 return 0;
189 ircp->irc_addr = s;
191 * Get the IP#
193 for (l = 0; ISDIGIT(c) && (i > 0); i--) {
194 l *= 10;
195 l += c - '0';
196 c = *s++;
199 if (i < 4)
200 return 0;
202 if (c != ' ')
203 return 0;
205 ircp->irc_ipnum = l;
206 s++;
207 i--;
208 c = *s;
209 if (!ISDIGIT(c))
210 return 0;
212 * Get the port#
214 for (l = 0; ISDIGIT(c) && (i > 0); i--) {
215 l *= 10;
216 l += c - '0';
217 c = *s++;
219 if (i < 3)
220 return 0;
221 if (strncmp(s, "\001\r\n", 3))
222 return 0;
223 s += 3;
224 ircp->irc_len = s - buf;
225 ircp->irc_port = l;
226 return 1;
230 int ippr_irc_new(fin, aps, nat)
231 fr_info_t *fin;
232 ap_session_t *aps;
233 nat_t *nat;
235 ircinfo_t *irc;
237 KMALLOC(irc, ircinfo_t *);
238 if (irc == NULL)
239 return -1;
241 fin = fin; /* LINT */
242 nat = nat; /* LINT */
244 aps->aps_data = irc;
245 aps->aps_psiz = sizeof(ircinfo_t);
247 bzero((char *)irc, sizeof(*irc));
248 return 0;
252 int ippr_irc_send(fin, nat)
253 fr_info_t *fin;
254 nat_t *nat;
256 char ctcpbuf[IPF_IRCBUFSZ], newbuf[IPF_IRCBUFSZ];
257 tcphdr_t *tcp, tcph, *tcp2 = &tcph;
258 int off, inc = 0, i, dlen;
259 size_t nlen = 0, olen;
260 struct in_addr swip;
261 u_short a5, sp;
262 ircinfo_t *irc;
263 fr_info_t fi;
264 nat_t *nat2;
265 u_int a1;
266 ip_t *ip;
267 mb_t *m;
268 #ifdef MENTAT
269 mb_t *m1;
270 #endif
272 m = fin->fin_m;
273 ip = fin->fin_ip;
274 tcp = (tcphdr_t *)fin->fin_dp;
275 bzero(ctcpbuf, sizeof(ctcpbuf));
276 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
278 #ifdef __sgi
279 dlen = fin->fin_plen - off;
280 #else
281 dlen = MSGDSIZE(m) - off;
282 #endif
283 if (dlen <= 0)
284 return 0;
285 COPYDATA(m, off, MIN(sizeof(ctcpbuf), dlen), ctcpbuf);
287 if (dlen <= 0)
288 return 0;
289 ctcpbuf[sizeof(ctcpbuf) - 1] = '\0';
290 *newbuf = '\0';
292 irc = nat->nat_aps->aps_data;
293 if (ippr_irc_complete(irc, ctcpbuf, dlen) == 0)
294 return 0;
297 * check that IP address in the PORT/PASV reply is the same as the
298 * sender of the command - prevents using PORT for port scanning.
300 if (irc->irc_ipnum != ntohl(nat->nat_inip.s_addr))
301 return 0;
303 a5 = irc->irc_port;
306 * Calculate new address parts for the DCC command
308 a1 = ntohl(ip->ip_src.s_addr);
309 olen = irc->irc_len;
310 i = irc->irc_addr - ctcpbuf;
311 i++;
312 (void) strncpy(newbuf, ctcpbuf, i);
313 /* DO NOT change these! */
314 #if defined(SNPRINTF) && defined(KERNEL)
315 SNPRINTF(newbuf, sizeof(newbuf) - i, "%u %u\001\r\n", a1, a5);
316 #else
317 (void) sprintf(newbuf, "%u %u\001\r\n", a1, a5);
318 #endif
320 nlen = strlen(newbuf);
321 inc = nlen - olen;
323 if ((inc + ip->ip_len) > 65535)
324 return 0;
326 #ifdef MENTAT
327 for (m1 = m; m1->b_cont; m1 = m1->b_cont)
329 if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) {
330 mblk_t *nm;
332 /* alloc enough to keep same trailer space for lower driver */
333 nm = allocb(nlen, BPRI_MED);
334 PANIC((!nm),("ippr_irc_out: allocb failed"));
336 nm->b_band = m1->b_band;
337 nm->b_wptr += nlen;
339 m1->b_wptr -= olen;
340 PANIC((m1->b_wptr < m1->b_rptr),
341 ("ippr_irc_out: cannot handle fragmented data block"));
343 linkb(m1, nm);
344 } else {
345 # if SOLARIS && defined(ICK_VALID)
346 if (m1->b_datap->db_struiolim == m1->b_wptr)
347 m1->b_datap->db_struiolim += inc;
348 m1->b_datap->db_struioflag &= ~STRUIO_IP;
349 # endif
350 m1->b_wptr += inc;
352 #else
353 if (inc < 0)
354 m_adj(m, inc);
355 /* the mbuf chain will be extended if necessary by m_copyback() */
356 #endif
357 COPYBACK(m, off, nlen, newbuf);
359 if (inc != 0) {
360 #if defined(MENTAT) || defined(__sgi)
361 register u_32_t sum1, sum2;
363 sum1 = ip->ip_len;
364 sum2 = ip->ip_len + inc;
366 /* Because ~1 == -2, We really need ~1 == -1 */
367 if (sum1 > sum2)
368 sum2--;
369 sum2 -= sum1;
370 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
372 fix_outcksum(fin, &ip->ip_sum, sum2);
373 #endif
374 ip->ip_len += inc;
378 * Add skeleton NAT entry for connection which will come back the
379 * other way.
381 sp = htons(a5);
383 * Don't allow the PORT command to specify a port < 1024 due to
384 * security crap.
386 if (ntohs(sp) < 1024)
387 return 0;
390 * The server may not make the connection back from port 20, but
391 * it is the most likely so use it here to check for a conflicting
392 * mapping.
394 bcopy((void *)fin, (void *)&fi, sizeof(fi));
395 fi.fin_data[0] = sp;
396 fi.fin_data[1] = fin->fin_data[1];
397 nat2 = nat_outlookup(fin, IPN_TCP, nat->nat_p, nat->nat_inip,
398 ip->ip_dst);
399 if (nat2 == NULL) {
400 bcopy((void *)fin, (void *)&fi, sizeof(fi));
401 bzero((char *)tcp2, sizeof(*tcp2));
402 tcp2->th_win = htons(8192);
403 tcp2->th_sport = sp;
404 tcp2->th_dport = 0; /* XXX - don't specify remote port */
405 fi.fin_data[0] = ntohs(sp);
406 fi.fin_data[1] = 0;
407 fi.fin_dp = (char *)tcp2;
408 fi.fin_fr = &ircnatfr;
409 fi.fin_dlen = sizeof(*tcp2);
410 fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
411 swip = ip->ip_src;
412 ip->ip_src = nat->nat_inip;
413 MUTEX_ENTER(&ipf_nat_new);
414 nat2 = nat_new(&fi, nat->nat_ptr, NULL,
415 NAT_SLAVE|IPN_TCP|SI_W_DPORT, NAT_OUTBOUND);
416 MUTEX_EXIT(&ipf_nat_new);
417 if (nat2 != NULL) {
418 (void) nat_proto(&fi, nat2, 0);
419 MUTEX_ENTER(&nat2->nat_lock);
420 nat_update(&fi, nat2);
421 MUTEX_EXIT(&nat2->nat_lock);
423 (void) fr_addstate(&fi, NULL, SI_W_DPORT);
425 ip->ip_src = swip;
427 return inc;
431 int ippr_irc_out(fin, aps, nat)
432 fr_info_t *fin;
433 ap_session_t *aps;
434 nat_t *nat;
436 aps = aps; /* LINT */
437 return ippr_irc_send(fin, nat);