in reply to Re^2: Perl and advanced networking question...
in thread Perl and advanced networking question...

As brother zwon has indicated above, the Net::RawIP module (and all its many friends) allows you to drive libpcap -- which appears to be pretty comprehensive...

I think your best bet is to send a RST in both directions -- telling your server, as soon as possible, to give up and telling the client to "go away". I guess you're then going to keep a look out for the "evil" IP address and bounce all further TCP open requests ?

You'll have to concentrate on the sequence numbers, and getting your RST packets in promptly -- I seem to remember that stacks will accept RST even if the sequence number is not exactly as expected... but I cannot remember the range of this tolerance.

On some systems you can open a raw socket: socket $ETH, PF_INET, SOCK_RAW, IPPROTO_RAW (where IPPROTO_RAW is 255). This socket can be used for output only. You can then send entire IP packets (complete with IP header) via the socket. The socket will fill in these IP header fields: (a) checksum; (b) source address, if zero; (c) packet id, if zero; and (d) total length. The socket will then send out the packet as per the destination address. If your system supports it, you may or may not find this easier than getting to grips with Net::RawIP et al.

The enclosed code certainly sends packets as required from my Linux box. YMMV. To do what you want requires picking apart the IP and TCP headers of your "evil" packet, and mungeing up suitable RST packets to send.

#!/bin/perl -w use strict ; use warnings ; use Socket ; use constant IPPROTO_RAW => 255 ; use constant DUMMY_ADDR => scalar(sockaddr_in(0, inet_aton('1.0.0.0') +)) ; my $ETH ; socket $ETH, PF_INET, SOCK_RAW, IPPROTO_RAW or die "$!" ; my $tcp = new_tcp({ src_ip => 0xABCD_1234, src_p => 54321, dst_ip => 0x1234_ABCD, dst_p => 12345, }) ; my $text = "Now is the time for all good men to come to the aid of the + party" ; for (1..4) { my $pkt = tcp_packet($tcp, $text) ; # Because $ETH is not connected, Perl requires a valid looking socka +ddr to send to. # However, the address is ignored on sockets opened SOCK_RAW, IPPROT +O_RAW ! send $ETH, $pkt, 0, DUMMY_ADDR or die "$!" ; $text .= "!" ; } ; # Construct new TCP "state". # # src_ip => source IP address (numeric) -- required # src_p => source port (numeric) -- required # dst_ip => destination IP address (numeric) -- required # dst_p => destination port (numeric) -- required # seq => initial sequence number (numeric) -- default = random +setting # a_seq => acknowledgement number (numeric) -- default = none # window => window size (numeric) -- default = 10000 # # ttl => TTL to use (numeric) -- default = 100 # tos => TIS to use (numeric) -- default = 0 sub new_tcp { my ($tcp) = @_ ; die "new_tcp: requires 'src_ip'" if !exists($tcp->{src_i +p}) ; die "new_tcp: requires 'src_p'" if !exists($tcp->{src_p +}) ; die "new_tcp: requires 'dst_ip'" if !exists($tcp->{dst_i +p}) ; die "new_tcp: requires 'dst_p'" if !exists($tcp->{dst_p +}) ; $tcp->{seq} = int(rand(0xFFFF_FFFF)) + 1 if !exists($tcp->{seq}) + ; $tcp->{a_seq} = undef if !exists($tcp->{a_seq +}) ; $tcp->{window} = 10000 if !exists($tcp->{windo +w}) ; $tcp->{ttl} = 100 if !exists($tcp->{ttl}) + ; $tcp->{tos} = 0 if !exists($tcp->{tos}) + ; $tcp->{proto} = 6 ; return $tcp ; } ; # Construct TCP packet (complete with IP header) # # Takes: $tcp -- ref:Hash, tcp state # src_p -- numeric -- required # dst_p -- numeric -- required # seq -- numeric -- required # window -- numeric -- required # # src_ip -- numeric -- required (as per + IP) # dst_ip -- numeric -- required (as per + IP) # proto -- numeric -- required (as per + IP) # ttl -- numeric -- default = 100 (as per + IP) # tos -- numeric -- default = 0 (as per + IP) # $data -- data to go # $r_st -- ref:Hash, tcp state to update (eg { window => 10 +} ); # # NB: given tcp state may include: # # urg => size of urgent data. If not zero, sets URG and PSH fl +ags # SYN => true Sets SYN flag # FIN => true Sets FIN flag # RST => true Sets RST flag # # This state is cleared when packet is returned. sub tcp_packet { my ($tcp, $data, $r_st) = @_ ; if ($r_st) { @{$tcp}{keys %$r_st} = values %$r_st ; } ; my $options = '' ; # No option handling, pro tem if (my $o = length($options) & 3) { $options .= "\0" x (4 - $o) ; } +; die "tcp_packet: requires 'src_p'" if !defined($tcp->{src_p}) ; die "tcp_packet: requires 'dst_p'" if !defined($tcp->{dst_p}) ; die "tcp_packet: requires 'seq'" if !defined($tcp->{seq}) ; die "tcp_packet: requires 'window'" if !defined($tcp->{window}) ; my $hlen = 20 + length($options) ; my $dlen = length($data) ; my $pseudo = pack('N N CCn', $tcp->{src_ip}, # N: Source IP $tcp->{dst_ip}, # N: Destination IP 0, # C: padding $tcp->{proto}, # C: protocol $hlen + $dlen # n: TCP Header Length + TCP +Data Length ) ; my $urg = $tcp->{urg} || 0 ; my $flags = $hlen << 10 ; # == ($hlen / 4) << 12 ! $flags |= 0x28 if $urg ; $flags |= 0x10 if defined($tcp->{a_seq}) ; $flags |= 0x04 if $tcp->{RST} ; $flags |= 0x02 if $tcp->{SYN} ; $flags |= 0x01 if $tcp->{FIN} ; my $csum = 0 ; my $dsum = unpack("%32n*", $pseudo . $data . (length($data) & 1 ? " +\0" : '')) ; my $header ; for (1..2) { $header = pack('nn N N nn nn A*', $tcp->{src_p}, # n: Source Port $tcp->{dst_p}, # n: Destination Port $tcp->{seq}, # N: Sequence Number $tcp->{a_seq} || 0, # N: Acknowledgement Number $flags, # n: Header Length & TCP Flag +s $tcp->{window}, # n: Window Size $csum, # n: Header Checksum $urg, # n: Urgent Pointer $options # A*: Options ) ; # my @h = unpack("N*", $header) ; # foreach (@h) { printf "%08X\n", $_ ; } ; $csum = unpack("%32n*", $header) + $dsum ; $csum = ( ~(($csum >> 16) + $csum)) & 0xFFFF ; } ; if ($csum != 0) { die "$csum" ; } ; delete $tcp->{urg} ; delete $tcp->{syn} ; delete $tcp->{fin} ; return ipv4_packet($tcp, $header . $data) ; } ; # Construct an IPv4 Packet # # Requires: $ipv4 -- ref:Hash, containing: # src_ip -- numeric -- required # dst_ip -- numeric -- required # proto -- numeric -- required # ttl -- numeric -- default = 100 # tos -- numeric -- default = 0 # $data -- the data ! sub ipv4_packet { my ($ipv4, $data) = @_ ; die "ipv4_packet: requires 'src_ip'" if !defined($ipv4->{src_ip}) ; die "ipv4_packet: requires 'dst_ip'" if !defined($ipv4->{dst_ip}) ; die "ipv4_packet: requires 'proto'" if !defined($ipv4->{proto}) ; my $ttl = $ipv4->{ttl} || 100 ; my $tos = $ipv4->{tos} || 0 ; my $options = '' ; # No option handling, pro tem if (my $o = length($options) & 3) { $options .= "\0" x (4 - $o) ; } +; my $csum = 0 ; my $hlen = 20 + length($options) ; my $dlen = length($data) ; my $header ; for (1..2) { $header = pack('CCn nn CCn N N A*', 0x40 + ($hlen / 4), # C: Version & Header Length +in "words" 0, # C: TOS $hlen + $dlen, # n: total packet length 0, # n: expect stack to set iden +tification 0, # n: no fragmentation $ttl, # C: TTL $ipv4->{proto}, # C: Protocol $csum, # n: Header Checksum $ipv4->{src_ip}, # N: Source IP $ipv4->{dst_ip}, # N: Destination IP $options # A*: Options ) ; $csum = unpack("%32n*", $header) ; $csum = ( ~(($csum >> 16) + $csum)) & 0xFFFF ; } ; if ($csum != 0) { die "$csum" ; } ; return $header . $data ; } ;