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
13 #define IPF_IRCBUFSZ 96 /* This *MUST* be >= 64! */
16 int ippr_irc_init
__P((void));
17 void ippr_irc_fini
__P((void));
18 int ippr_irc_new
__P((fr_info_t
*, ap_session_t
*, nat_t
*));
19 int ippr_irc_out
__P((fr_info_t
*, ap_session_t
*, nat_t
*));
20 int ippr_irc_send
__P((fr_info_t
*, nat_t
*));
21 int ippr_irc_complete
__P((ircinfo_t
*, char *, size_t));
22 u_short ipf_irc_atoi
__P((char **));
24 static frentry_t ircnatfr
;
26 int irc_proxy_init
= 0;
30 * Initialize local structures.
34 bzero((char *)&ircnatfr
, sizeof(ircnatfr
));
36 ircnatfr
.fr_flags
= FR_INQUE
|FR_PASS
|FR_QUICK
|FR_KEEPSTATE
;
37 MUTEX_INIT(&ircnatfr
.fr_lock
, "IRC proxy rule lock");
46 if (irc_proxy_init
== 1) {
47 MUTEX_DESTROY(&ircnatfr
.fr_lock
);
53 const char *ippr_irc_dcctypes
[] = {
54 "CHAT ", /* CHAT chat ipnumber portnumber */
55 "SEND ", /* SEND filename ipnumber portnumber */
64 * :A PRIVMSG B :^ADCC CHAT chat 0 0^A\r\n
65 * PRIVMSG B ^ADCC CHAT chat 0 0^A\r\n
69 int ippr_irc_complete(ircp
, buf
, len
)
88 if ((c
!= ':') && (c
!= 'P'))
93 * Loosely check that the source is a nickname of some sort
101 for (c
= *s
; !ISSPACE(c
) && (i
> 0); i
--)
108 ircp
->irc_snick
= NULL
;
111 * Check command string
113 if (strncmp(s
, "PRIVMSG ", 8))
121 * Loosely check that the destination is a nickname of some sort
125 for (; !ISSPACE(c
) && (i
> 0); i
--)
133 * Look for a ^A to start the DCC
141 if (strncmp(s
, "\001DCC ", 4))
148 * Check for a recognised DCC command
150 for (j
= 0, k
= 0; ippr_irc_dcctypes
[j
]; j
++) {
151 k
= MIN(strlen(ippr_irc_dcctypes
[j
]), i
);
152 if (!strncmp(ippr_irc_dcctypes
[j
], s
, k
))
155 if (!ippr_irc_dcctypes
[j
])
172 for (; (c
!= ' ') && (c
!= '\001') && (i
> 0); i
--)
175 if (c
== '\001') /* In reality a ^A can quote another ^A...*/
190 for (l
= 0; ISDIGIT(c
) && (i
> 0); i
--) {
211 for (l
= 0; ISDIGIT(c
) && (i
> 0); i
--) {
218 if (strncmp(s
, "\001\r\n", 3))
221 ircp
->irc_len
= s
- buf
;
227 int ippr_irc_new(fin
, aps
, nat
)
234 KMALLOC(irc
, ircinfo_t
*);
238 fin
= fin
; /* LINT */
239 nat
= nat
; /* LINT */
242 aps
->aps_psiz
= sizeof(ircinfo_t
);
244 bzero((char *)irc
, sizeof(*irc
));
249 int ippr_irc_send(fin
, nat
)
253 char ctcpbuf
[IPF_IRCBUFSZ
], newbuf
[IPF_IRCBUFSZ
];
254 tcphdr_t
*tcp
, tcph
, *tcp2
= &tcph
;
255 int off
, inc
= 0, i
, dlen
;
256 size_t nlen
= 0, olen
;
271 tcp
= (tcphdr_t
*)fin
->fin_dp
;
272 bzero(ctcpbuf
, sizeof(ctcpbuf
));
273 off
= (char *)tcp
- (char *)ip
+ (TCP_OFF(tcp
) << 2) + fin
->fin_ipoff
;
276 dlen
= fin
->fin_plen
- off
;
278 dlen
= MSGDSIZE(m
) - off
;
282 COPYDATA(m
, off
, MIN(sizeof(ctcpbuf
), dlen
), ctcpbuf
);
286 ctcpbuf
[sizeof(ctcpbuf
) - 1] = '\0';
289 irc
= nat
->nat_aps
->aps_data
;
290 if (ippr_irc_complete(irc
, ctcpbuf
, dlen
) == 0)
294 * check that IP address in the PORT/PASV reply is the same as the
295 * sender of the command - prevents using PORT for port scanning.
297 if (irc
->irc_ipnum
!= ntohl(nat
->nat_inip
.s_addr
))
303 * Calculate new address parts for the DCC command
305 a1
= ntohl(ip
->ip_src
.s_addr
);
307 i
= irc
->irc_addr
- ctcpbuf
;
309 (void) strncpy(newbuf
, ctcpbuf
, i
);
310 /* DO NOT change these! */
311 #if defined(SNPRINTF) && defined(KERNEL)
312 SNPRINTF(newbuf
, sizeof(newbuf
) - i
, "%u %u\001\r\n", a1
, a5
);
314 (void) sprintf(newbuf
, "%u %u\001\r\n", a1
, a5
);
317 nlen
= strlen(newbuf
);
320 if ((inc
+ ip
->ip_len
) > 65535)
324 for (m1
= m
; m1
->b_cont
; m1
= m1
->b_cont
)
326 if ((inc
> 0) && (m1
->b_datap
->db_lim
- m1
->b_wptr
< inc
)) {
329 /* alloc enough to keep same trailer space for lower driver */
330 nm
= allocb(nlen
, BPRI_MED
);
331 PANIC((!nm
),("ippr_irc_out: allocb failed"));
333 nm
->b_band
= m1
->b_band
;
337 PANIC((m1
->b_wptr
< m1
->b_rptr
),
338 ("ippr_irc_out: cannot handle fragmented data block"));
342 # if SOLARIS && defined(ICK_VALID)
343 if (m1
->b_datap
->db_struiolim
== m1
->b_wptr
)
344 m1
->b_datap
->db_struiolim
+= inc
;
345 m1
->b_datap
->db_struioflag
&= ~STRUIO_IP
;
352 /* the mbuf chain will be extended if necessary by m_copyback() */
354 COPYBACK(m
, off
, nlen
, newbuf
);
357 #if defined(MENTAT) || defined(__sgi)
358 register u_32_t sum1
, sum2
;
361 sum2
= ip
->ip_len
+ inc
;
363 /* Because ~1 == -2, We really need ~1 == -1 */
367 sum2
= (sum2
& 0xffff) + (sum2
>> 16);
369 fix_outcksum(fin
, &ip
->ip_sum
, sum2
);
375 * Add skeleton NAT entry for connection which will come back the
380 * Don't allow the PORT command to specify a port < 1024 due to
383 if (ntohs(sp
) < 1024)
387 * The server may not make the connection back from port 20, but
388 * it is the most likely so use it here to check for a conflicting
391 bcopy((caddr_t
)fin
, (caddr_t
)&fi
, sizeof(fi
));
393 fi
.fin_data
[1] = fin
->fin_data
[1];
394 nat2
= nat_outlookup(fin
, IPN_TCP
, nat
->nat_p
, nat
->nat_inip
,
397 bcopy((caddr_t
)fin
, (caddr_t
)&fi
, sizeof(fi
));
398 bzero((char *)tcp2
, sizeof(*tcp2
));
399 tcp2
->th_win
= htons(8192);
401 tcp2
->th_dport
= 0; /* XXX - don't specify remote port */
402 fi
.fin_data
[0] = ntohs(sp
);
404 fi
.fin_dp
= (char *)tcp2
;
405 fi
.fin_fr
= &ircnatfr
;
406 fi
.fin_dlen
= sizeof(*tcp2
);
407 fi
.fin_plen
= fi
.fin_hlen
+ sizeof(*tcp2
);
409 ip
->ip_src
= nat
->nat_inip
;
410 MUTEX_ENTER(&ipf_nat_new
);
411 nat2
= nat_new(&fi
, nat
->nat_ptr
, NULL
,
412 NAT_SLAVE
|IPN_TCP
|SI_W_DPORT
, NAT_OUTBOUND
);
413 MUTEX_EXIT(&ipf_nat_new
);
415 (void) nat_proto(&fi
, nat2
, 0);
416 MUTEX_ENTER(&nat2
->nat_lock
);
417 nat_update(&fi
, nat2
);
418 MUTEX_EXIT(&nat2
->nat_lock
);
420 (void) fr_addstate(&fi
, NULL
, SI_W_DPORT
);
428 int ippr_irc_out(fin
, aps
, nat
)
433 aps
= aps
; /* LINT */
434 return ippr_irc_send(fin
, nat
);