#
# icmp.rb -- ICMPModule
#
# Copyright (C) 2000 GOTOU YUUZOU <gotoyuzo@notwork.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $Id: icmp.rb,v 1.2 2001/09/20 17:13:42 gotoyuzo Exp $
require 'socket'
module ICMPModule
# Protocol
IPPROTO_IP = 0
IPPROTO_ICMP = 1
# Type and code field values
ICMP_ECHOREPLY = 0 # echo reply
ICMP_UNREACH = 3 # dest unreachable, codes:
ICMP_UNREACH_NET = 0 # bad net
ICMP_UNREACH_HOST = 1 # bad host
ICMP_UNREACH_PROTOCOL = 2 # bad protocol
ICMP_UNREACH_PORT = 3 # bad port
ICMP_UNREACH_NEEDFRAG = 4 # IP_DF caused drop
ICMP_UNREACH_SRCFAIL = 5 # src route failed
ICMP_UNREACH_NET_UNKNOWN = 6 # unknown net
ICMP_UNREACH_HOST_UNKNOWN = 7 # unknown host
ICMP_UNREACH_ISOLATED = 8 # src host isolated
ICMP_UNREACH_NET_PROHIB = 9 # prohibited access
ICMP_UNREACH_HOST_PROHIB = 10 # ditto
ICMP_UNREACH_TOSNET = 11 # bad tos for net
ICMP_UNREACH_TOSHOST = 12 # bad tos for host
ICMP_UNREACH_ADMIN_PROHIBIT = 13 # communication administratively
# prohibited
ICMP_SOURCEQUENCH = 4 # packet lost, slow down
ICMP_REDIRECT = 5 # shorter route, codes:
ICMP_REDIRECT_NET = 0 # for network
ICMP_REDIRECT_HOST = 1 # for host
ICMP_REDIRECT_TOSNET = 2 # for tos and net
ICMP_REDIRECT_TOSHOST = 3 # for tos and host
ICMP_ECHO = 8 # echo service
ICMP_ROUTERADVERT = 9 # router advertisement (RFC1256)
ICMP_ROUTERSOLICIT = 10 # router solicitation (RFC1256)
ICMP_TIMXCEED = 11 # time exceeded, code:
ICMP_TIMXCEED_INTRANS = 0 # ttl==0 in transit
ICMP_TIMXCEED_REASS = 1 # ttl==0 in reass
ICMP_PARAMPROB = 12 # ip header bad, code:
ICMP_PARAMPROB_OPTABSENT = 1 # req. opt. absent
ICMP_TSTAMP = 13 # timestamp request
ICMP_TSTAMPREPLY = 14 # timestamp reply
ICMP_IREQ = 15 # information request
ICMP_IREQREPLY = 16 # information reply
ICMP_MASKREQ = 17 # address mask request (RFC950)
ICMP_MASKREPLY = 18 # address mask reply (RFC950)
ICMP_MINLEN = 8
ICMP_TSLEN = 20
ICMP_MASKLEN = 12
ICMP_ADVLENMIN = 36
class IMCPError_rb < StandardError; end
class IP_rb < String
def self.new(s=nil); s ? super(s) : super("\0" * 20); end
def ip_v; (self[0] >> 4) & 0xf end
def ip_hl; self[0] & 0xf end
def ip_tos; self[1]; end
def ip_len; self[2..3].unpack("n")[0]; end
def ip_id; self[4..5].unpack("n")[0]; end
def ip_off; self[6..7].unpack("n")[0]; end
def ip_ttl; self[8]; end
def ip_p; self[9]; end
def ip_sum; self[10..11].unpack("n")[0]; end
def ip_src; "%d.%d.%d.%d" % [self[12], self[13], self[14], self[15]]; end
def ip_dst; "%d.%d.%d.%d" % [self[16], self[17], self[18], self[19]]; end
def body; self[(ip_hl*4)..-1]; end
end
class ICMP_rb < String
def self.new(s=nil); s ? super(s) : super("\0" * ICMP_ADVLENMIN); end
def icmp_type; self[0]; end
def icmp_type=v; self[0]=v; end
def icmp_code; self[1]; end
def icmp_code=v; self[1]=v; end
def icmp_cksum; self[2..3].unpack("n")[0]; end
def icmp_cksum=v; self[2..3]=[v].pack("n"); end
def icmp_id; self[4..5].unpack("n")[0]; end
def icmp_id=v; self[4..5]=[v].pack("n"); end
def icmp_seq; self[6..7].unpack("n")[0]; end
def icmp_seq=v; self[6..7]=[v].pack("n"); end
def icmp_data; self[8..-1]; end
def icmp_data=v; self[8..-1]=v; end
def icmp_gwaddr; "%d.%d.%d.%d" % [self[4], self[5], self[6], self[7]]; end
def icmp_ip; IP.new(self[8..-1]); end
def icmp_ip=v; self[8..-1]=v; end
def truncate
olen = self.size
case self.icmp_type
when ICMP_IREQ, ICMP_IREQREPLY
nlen = ICMP_MINLEN
when ICMP_UNREACH, ICMP_TIMXCEED, ICMP_PARAMPROB,
ICMP_SOURCEQUENCH, ICMP_REDIRECT
nlen = ICMP_ADVLENMIN
when ICMP_TSTAMP, ICMP_TSTAMPREPLY
nlen = ICMP_TSLEN
when ICMP_ROUTERADVERT, ICMP_ROUTERSOLICIT
nlen = icmp_advlen
when ICMP_MASKREQ, ICMP_MASKREPLY
nlen = ICMP_MASKLEN
when ICMP_ECHO, ICMP_ECHOREPLY
nlen = olen
else
raise ICMPError, "unknown icmp_type %d" % self.icmp_type
end
self[nlen..-1] = ""
end
def icmp_advlen
8 + (icmp_ip.ip_hl * 4) + 8
end
def set_cksum
self.icmp_cksum = 0
sum = 0
self.unpack("n*").each{ |i| sum += i }
sum += (self[-1] << 8) if self.size % 2 == 1
sum = (sum & 0xffff) + (sum >> 16)
sum += (sum >> 16)
self.icmp_cksum = ~sum & 0xffff
self
end
def setup
truncate
set_cksum
end
end
class ICMPSocket < Socket
def ICMPSocket.new
super("AF_INET", "SOCK_RAW", IPPROTO_ICMP)
end
end
def make_sockaddr_in(family, port, addr)
s = [ family ].pack("S")
s << [ port ].pack("n") # network byteorder
s << addr
s << "\0" * 8
s
end
def split(s)
ip = IP.new s
len = ip.ip_hl * 4 # ip_hl is header length in 32 bit word.
ip[len..-1] = ""
[ ip, ICMP.new(s[len..-1]) ]
end
begin
require 'icmpmodule'
IP = IP_c
ICMP = ICMP_c
ICMPError = ICMPError_c
rescue LoadError
IP = IP_rb
ICMP = ICMP_rb
ICMPError = ICMPError_rb
end
end
syntax highlighted by Code2HTML, v. 0.9.1