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
11 #include <sys/cdefs.h>
12 __KERNEL_RCSID(1, "$NetBSD$");
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.
37 bzero((char *)&ircnatfr
, sizeof(ircnatfr
));
39 ircnatfr
.fr_flags
= FR_INQUE
|FR_PASS
|FR_QUICK
|FR_KEEPSTATE
;
40 MUTEX_INIT(&ircnatfr
.fr_lock
, "IRC proxy rule lock");
49 if (irc_proxy_init
== 1) {
50 MUTEX_DESTROY(&ircnatfr
.fr_lock
);
56 const char *ippr_irc_dcctypes
[] = {
57 "CHAT ", /* CHAT chat ipnumber portnumber */
58 "SEND ", /* SEND filename ipnumber portnumber */
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
)
91 if ((c
!= ':') && (c
!= 'P'))
96 * Loosely check that the source is a nickname of some sort
104 for (c
= *s
; !ISSPACE(c
) && (i
> 0); i
--)
111 ircp
->irc_snick
= NULL
;
114 * Check command string
116 if (strncmp(s
, "PRIVMSG ", 8))
124 * Loosely check that the destination is a nickname of some sort
128 for (; !ISSPACE(c
) && (i
> 0); i
--)
136 * Look for a ^A to start the DCC
144 if (strncmp(s
, "\001DCC ", 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
))
158 if (!ippr_irc_dcctypes
[j
])
175 for (; (c
!= ' ') && (c
!= '\001') && (i
> 0); i
--)
178 if (c
== '\001') /* In reality a ^A can quote another ^A...*/
193 for (l
= 0; ISDIGIT(c
) && (i
> 0); i
--) {
214 for (l
= 0; ISDIGIT(c
) && (i
> 0); i
--) {
221 if (strncmp(s
, "\001\r\n", 3))
224 ircp
->irc_len
= s
- buf
;
230 int ippr_irc_new(fin
, aps
, nat
)
237 KMALLOC(irc
, ircinfo_t
*);
241 fin
= fin
; /* LINT */
242 nat
= nat
; /* LINT */
245 aps
->aps_psiz
= sizeof(ircinfo_t
);
247 bzero((char *)irc
, sizeof(*irc
));
252 int ippr_irc_send(fin
, 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
;
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
;
279 dlen
= fin
->fin_plen
- off
;
281 dlen
= MSGDSIZE(m
) - off
;
285 COPYDATA(m
, off
, MIN(sizeof(ctcpbuf
), dlen
), ctcpbuf
);
289 ctcpbuf
[sizeof(ctcpbuf
) - 1] = '\0';
292 irc
= nat
->nat_aps
->aps_data
;
293 if (ippr_irc_complete(irc
, ctcpbuf
, dlen
) == 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
))
306 * Calculate new address parts for the DCC command
308 a1
= ntohl(ip
->ip_src
.s_addr
);
310 i
= irc
->irc_addr
- ctcpbuf
;
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
);
317 (void) sprintf(newbuf
, "%u %u\001\r\n", a1
, a5
);
320 nlen
= strlen(newbuf
);
323 if ((inc
+ ip
->ip_len
) > 65535)
327 for (m1
= m
; m1
->b_cont
; m1
= m1
->b_cont
)
329 if ((inc
> 0) && (m1
->b_datap
->db_lim
- m1
->b_wptr
< inc
)) {
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
;
340 PANIC((m1
->b_wptr
< m1
->b_rptr
),
341 ("ippr_irc_out: cannot handle fragmented data block"));
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
;
355 /* the mbuf chain will be extended if necessary by m_copyback() */
357 COPYBACK(m
, off
, nlen
, newbuf
);
360 #if defined(MENTAT) || defined(__sgi)
361 register u_32_t sum1
, sum2
;
364 sum2
= ip
->ip_len
+ inc
;
366 /* Because ~1 == -2, We really need ~1 == -1 */
370 sum2
= (sum2
& 0xffff) + (sum2
>> 16);
372 fix_outcksum(fin
, &ip
->ip_sum
, sum2
);
378 * Add skeleton NAT entry for connection which will come back the
383 * Don't allow the PORT command to specify a port < 1024 due to
386 if (ntohs(sp
) < 1024)
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
394 bcopy((void *)fin
, (void *)&fi
, sizeof(fi
));
396 fi
.fin_data
[1] = fin
->fin_data
[1];
397 nat2
= nat_outlookup(fin
, IPN_TCP
, nat
->nat_p
, nat
->nat_inip
,
400 bcopy((void *)fin
, (void *)&fi
, sizeof(fi
));
401 bzero((char *)tcp2
, sizeof(*tcp2
));
402 tcp2
->th_win
= htons(8192);
404 tcp2
->th_dport
= 0; /* XXX - don't specify remote port */
405 fi
.fin_data
[0] = ntohs(sp
);
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
);
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
);
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
);
431 int ippr_irc_out(fin
, aps
, nat
)
436 aps
= aps
; /* LINT */
437 return ippr_irc_send(fin
, nat
);