/* * icmp_packet.c * * $Id: icmp_packet.c,v 1.1.1.1 1999/10/27 09:54:38 fukusima Exp $ * * Copyright (C) 1999 Masaki Fukushima */ #include "ruby_pcap.h" /* rfc1256 */ #ifndef ICMP_ROUTERADVERT #define ICMP_ROUTERADVERT 9 #endif #ifndef ICMP_ROUTERSOLICIT #define ICMP_ROUTERSOLICIT 10 #endif /* rfc1393 */ #ifndef ICMP_TROUTE #define ICMP_TROUTE 30 #endif /* rfc1788 */ #ifndef ICMP_DOMAIN #define ICMP_DOMAIN 37 #endif #ifndef ICMP_DOMAINREPLY #define ICMP_DOMAINREPLY 38 #endif /* rfc1700 */ #ifndef ICMP_UNREACH_NET_UNKNOWN #define ICMP_UNREACH_NET_UNKNOWN 6 #endif #ifndef ICMP_UNREACH_HOST_UNKNOWN #define ICMP_UNREACH_HOST_UNKNOWN 7 #endif #ifndef ICMP_UNREACH_ISOLATED #define ICMP_UNREACH_ISOLATED 8 #endif #ifndef ICMP_UNREACH_NET_PROHIB #define ICMP_UNREACH_NET_PROHIB 9 #endif #ifndef ICMP_UNREACH_HOST_PROHIB #define ICMP_UNREACH_HOST_PROHIB 10 #endif #ifndef ICMP_UNREACH_TOSNET #define ICMP_UNREACH_TOSNET 11 #endif #ifndef ICMP_UNREACH_TOSHOST #define ICMP_UNREACH_TOSHOST 12 #endif /* rfc1716 */ #ifndef ICMP_UNREACH_FILTER_PROHIB #define ICMP_UNREACH_FILTER_PROHIB 13 #endif #ifndef ICMP_UNREACH_HOST_PRECEDENCE #define ICMP_UNREACH_HOST_PRECEDENCE 14 #endif #ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF #define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 #endif #ifndef ICMP_PARAMPROB_OPTABSENT #define ICMP_PARAMPROB_OPTABSENT 1 #endif #define ICMP_HDR(pkt) ((struct icmp *)LAYER4_HDR(pkt)) #define ICMP_DATA(pkt) ((u_char *)LAYER5_HDR(pkt)) #define ICMP_DATALEN(pkt) \ (ntohs(IP_HDR(pkt)->ip_len) - (IP_HDR(pkt)->ip_hl * 4 + 8)) #define ICMP_CAPLEN(pkt) (pkt->hdr.pkthdr.caplen - pkt->hdr.layer4_off) VALUE cICMPPacket; #define CheckTruncateICMP(pkt, need) \ CheckTruncate(pkt, pkt->hdr.layer4_off, need, "truncated ICMP") struct icmp_type_info { char *name; VALUE klass; }; static struct icmp_type_info icmp_types[] = { {/* 0 */ "echo reply" }, {},{}, {/* 3 */ "unreachable" }, {/* 4 */ "source quench" }, {/* 5 */ "redirect" }, {},{}, {/* 8 */ "echo request" }, {/* 9 */ "router advertisement" }, {/* 10 */ "router solicitation" }, {/* 11 */ "time exceeded" }, {/* 12 */ "parameter problem" }, {/* 13 */ "time stamp request" }, {/* 14 */ "time stamp reply" }, {/* 15 */ "information request" }, {/* 16 */ "information reply" }, {/* 17 */ "address mask request" }, {/* 18 */ "address mask reply" }, {},{},{},{},{},{},{},{},{},{},{}, {/* 30 */ "traceroute" }, {},{},{},{},{},{}, {/* 37 */ "domain name request" }, {/* 38 */ "domain name reply" } #define ICMP_TYPE_MAX 38 }; VALUE setup_icmp_packet(pkt, tl_len) struct packet_object *pkt; int tl_len; { VALUE klass = cICMPPacket; if (tl_len >= 1) { struct icmp *icmp = ICMP_HDR(pkt); if (icmp->icmp_type <= ICMP_TYPE_MAX && icmp_types[icmp->icmp_type].klass) { klass = icmp_types[icmp->icmp_type].klass; } } return klass; } #define ICMPP_METHOD(func, need, val) \ static VALUE\ (func)(self)\ VALUE self;\ {\ struct packet_object *pkt;\ struct icmp *icmp;\ GetPacket(self, pkt);\ CheckTruncateICMP(pkt, (need));\ icmp = ICMP_HDR(pkt);\ return (val);\ } /* * Common methods (icmp_type independent) */ ICMPP_METHOD(icmpp_type, 1, INT2FIX(icmp->icmp_type)) ICMPP_METHOD(icmpp_code, 2, INT2FIX(icmp->icmp_code)) ICMPP_METHOD(icmpp_cksum, 4, INT2FIX(ntohs(icmp->icmp_cksum))) ICMPP_METHOD(icmpp_typestr, 1, (icmp->icmp_type <= ICMP_TYPE_MAX &&icmp_types[icmp->icmp_type].name) ? rb_str_new2(icmp_types[icmp->icmp_type].name) : rb_obj_as_string(INT2FIX(icmp->icmp_type))) /* * icmp_type specific methods */ ICMPP_METHOD(icmpp_pptr, 5, INT2FIX(icmp->icmp_pptr)) ICMPP_METHOD(icmpp_gwaddr, 8, new_ipaddr(&icmp->icmp_gwaddr)) ICMPP_METHOD(icmpp_id, 6, INT2FIX(ntohs(icmp->icmp_id))) ICMPP_METHOD(icmpp_seq, 8, INT2FIX(ntohs(icmp->icmp_seq))) #ifdef WORDS_BIGENDIAN ICMPP_METHOD(icmpp_seqle, 8, INT2FIX(((0x00ff&icmp->icmp_seq)<<8) + (icmp->icmp_seq >> 8))) #else ICMPP_METHOD(icmpp_seqle, 8, INT2FIX(icmp->icmp_seq)) #endif /* rfc1191 */ struct mtu_discovery { u_short unused; u_short nextmtu; }; #define MTUD(icmp) ((struct mtu_discovery *)&icmp->icmp_void) static VALUE icmpp_nextmtu(self) VALUE self; { struct packet_object *pkt; struct icmp *icmp; GetPacket(self, pkt); CheckTruncateICMP(pkt, 8); icmp = ICMP_HDR(pkt); if (icmp->icmp_code != ICMP_UNREACH_NEEDFRAG) rb_raise(rb_eRuntimeError, "not ICMP_UNREACH_NEEDFRAG"); return INT2FIX(ntohs(MTUD(icmp)->nextmtu)); } /* rfc1256 */ struct ih_rdiscovery { u_char num_addrs; u_char wpa; u_short lifetime; }; #define IHRD(icmp) ((struct ih_rdiscovery *)&icmp->icmp_void) struct id_rdiscovery { struct in_addr ird_addr; long ird_pref; }; #define IDRD(icmp) ((struct id_rdiscovery *)icmp->icmp_data) ICMPP_METHOD(icmpp_num_addrs, 5, INT2FIX(IHRD(icmp)->num_addrs)) ICMPP_METHOD(icmpp_wpa, 6, INT2FIX(IHRD(icmp)->wpa)) ICMPP_METHOD(icmpp_lifetime, 8, INT2FIX(ntohs(IHRD(icmp)->lifetime))) static VALUE icmpp_radv(self, ind) VALUE self, ind; { struct packet_object *pkt; struct icmp *icmp; int i = NUM2INT(ind); VALUE ary; GetPacket(self, pkt); CheckTruncateICMP(pkt, 5); if (i > IHRD(icmp)->num_addrs) rb_raise(rb_eRuntimeError, "num_addrs = %d, requested radv(%d)", (int)IHRD(icmp)->num_addrs, i); CheckTruncateICMP(pkt, 8 + i*8); icmp = ICMP_HDR(pkt); ary = rb_ary_new(); rb_ary_push(ary, new_ipaddr(&IDRD(icmp)->ird_addr)); rb_ary_push(ary, INT2NUM(ntohl(IDRD(icmp)->ird_pref))); return ary; } #define time_new_msec(t) rb_time_new((t)/1000, (t)%1000 * 1000) ICMPP_METHOD(icmpp_otime, 12, time_new_msec(ntohl(icmp->icmp_otime))) ICMPP_METHOD(icmpp_rtime, 16, time_new_msec(ntohl(icmp->icmp_rtime))) ICMPP_METHOD(icmpp_ttime, 20, time_new_msec(ntohl(icmp->icmp_ttime))) static VALUE icmpp_ip(self) VALUE self; { struct packet_object *pkt; struct icmp *icmp; struct pcap_pkthdr pkthdr; GetPacket(self, pkt); CheckTruncateICMP(pkt, 9); icmp = ICMP_HDR(pkt); pkthdr.caplen = ICMP_CAPLEN(pkt) - 8; pkthdr.len = 0; pkthdr.ts.tv_sec = 0; pkthdr.ts.tv_usec = 0; return new_packet((char *)&icmp->icmp_ip, &pkthdr, DLT_RAW); } ICMPP_METHOD(icmpp_mask, 12, UINT32_2_NUM(ntohl(icmp->icmp_mask))) ICMPP_METHOD(icmpp_data, 9, rb_str_new(icmp->icmp_data, ICMP_CAPLEN(pkt)-8)) /* rfc1393 */ struct traceroute { u_short ohc; u_short rhc; u_long lspeed; u_long lmtu; }; #define TROUTE(icmp) ((struct traceroute *)icmp->icmp_data) ICMPP_METHOD(icmpp_ohc, 10, INT2FIX(ntohs(TROUTE(icmp)->ohc))) ICMPP_METHOD(icmpp_rhc, 12, INT2FIX(ntohs(TROUTE(icmp)->rhc))) ICMPP_METHOD(icmpp_lspeed, 16, UINT32_2_NUM(ntohl(TROUTE(icmp)->lspeed))) ICMPP_METHOD(icmpp_lmtu, 20, UINT32_2_NUM(ntohl(TROUTE(icmp)->lmtu))) /* rfc1788 */ struct domain_reply { u_long ttl; char names[1]; }; #define DOMAIN(icmp) ((struct domain_reply *)icmp->icmp_data) ICMPP_METHOD(icmpp_ttl, 12, UINT32_2_NUM(ntohl(DOMAIN(icmp)->ttl))) void Init_icmp_packet(void) { VALUE klass; rb_define_const(mPcap, "ICMP_ECHOREPLY", INT2NUM(ICMP_ECHOREPLY)); rb_define_const(mPcap, "ICMP_UNREACH", INT2NUM(ICMP_UNREACH)); rb_define_const(mPcap, "ICMP_SOURCEQUENCH",INT2NUM(ICMP_SOURCEQUENCH)); rb_define_const(mPcap, "ICMP_REDIRECT", INT2NUM(ICMP_REDIRECT)); rb_define_const(mPcap, "ICMP_ECHO", INT2NUM(ICMP_ECHO)); rb_define_const(mPcap, "ICMP_TIMXCEED", INT2NUM(ICMP_TIMXCEED)); rb_define_const(mPcap, "ICMP_PARAMPROB", INT2NUM(ICMP_PARAMPROB)); rb_define_const(mPcap, "ICMP_TSTAMP", INT2NUM(ICMP_TSTAMP)); rb_define_const(mPcap, "ICMP_TSTAMPREPLY", INT2NUM(ICMP_TSTAMPREPLY)); rb_define_const(mPcap, "ICMP_IREQ", INT2NUM(ICMP_IREQ)); rb_define_const(mPcap, "ICMP_IREQREPLY", INT2NUM(ICMP_IREQREPLY)); rb_define_const(mPcap, "ICMP_MASKREQ", INT2NUM(ICMP_MASKREQ)); rb_define_const(mPcap, "ICMP_MASKREPLY", INT2NUM(ICMP_MASKREPLY)); /* UNREACH codes */ rb_define_const(mPcap, "ICMP_UNREACH_NET", INT2NUM(ICMP_UNREACH_NET)); rb_define_const(mPcap, "ICMP_UNREACH_HOST", INT2NUM(ICMP_UNREACH_HOST)); rb_define_const(mPcap, "ICMP_UNREACH_PROTOCOL", INT2NUM(ICMP_UNREACH_PROTOCOL)); rb_define_const(mPcap, "ICMP_UNREACH_PORT", INT2NUM(ICMP_UNREACH_PORT)); rb_define_const(mPcap, "ICMP_UNREACH_NEEDFRAG", INT2NUM(ICMP_UNREACH_NEEDFRAG)); rb_define_const(mPcap, "ICMP_UNREACH_SRCFAIL", INT2NUM(ICMP_UNREACH_SRCFAIL)); rb_define_const(mPcap, "ICMP_UNREACH_NET_UNKNOWN", INT2NUM(ICMP_UNREACH_NET_UNKNOWN)); rb_define_const(mPcap, "ICMP_UNREACH_HOST_UNKNOWN", INT2NUM(ICMP_UNREACH_HOST_UNKNOWN)); rb_define_const(mPcap, "ICMP_UNREACH_ISOLATED", INT2NUM(ICMP_UNREACH_ISOLATED)); rb_define_const(mPcap, "ICMP_UNREACH_NET_PROHIB", INT2NUM(ICMP_UNREACH_NET_PROHIB)); rb_define_const(mPcap, "ICMP_UNREACH_HOST_PROHIB", INT2NUM(ICMP_UNREACH_HOST_PROHIB)); rb_define_const(mPcap, "ICMP_UNREACH_TOSNET", INT2NUM(ICMP_UNREACH_TOSNET)); rb_define_const(mPcap, "ICMP_UNREACH_TOSHOST", INT2NUM(ICMP_UNREACH_TOSHOST)); rb_define_const(mPcap, "ICMP_UNREACH_FILTER_PROHIB", INT2NUM(ICMP_UNREACH_FILTER_PROHIB)); rb_define_const(mPcap, "ICMP_UNREACH_HOST_PRECEDENCE", INT2NUM(ICMP_UNREACH_HOST_PRECEDENCE)); rb_define_const(mPcap, "ICMP_UNREACH_PRECEDENCE_CUTOFF", INT2NUM(ICMP_UNREACH_PRECEDENCE_CUTOFF)); /* REDIRECT codes */ rb_define_const(mPcap, "ICMP_REDIRECT_NET", INT2NUM(ICMP_REDIRECT_NET)); rb_define_const(mPcap, "ICMP_REDIRECT_HOST", INT2NUM(ICMP_REDIRECT_HOST)); rb_define_const(mPcap, "ICMP_REDIRECT_TOSNET", INT2NUM(ICMP_REDIRECT_TOSNET)); rb_define_const(mPcap, "ICMP_REDIRECT_TOSHOST", INT2NUM(ICMP_REDIRECT_TOSHOST)); /* TIMEXCEED codes */ rb_define_const(mPcap, "ICMP_TIMXCEED_INTRANS", INT2NUM(ICMP_TIMXCEED_INTRANS)); rb_define_const(mPcap, "ICMP_TIMXCEED_REASS", INT2NUM(ICMP_TIMXCEED_REASS)); /* PARAMPROB code */ rb_define_const(mPcap, "ICMP_PARAMPROB_OPTABSENT", INT2NUM(ICMP_PARAMPROB_OPTABSENT)); cICMPPacket = rb_define_class_under(mPcap, "ICMPPacket", cIPPacket); rb_define_method(cICMPPacket, "icmp_type", icmpp_type, 0); rb_define_method(cICMPPacket, "icmp_typestr", icmpp_typestr, 0); rb_define_method(cICMPPacket, "icmp_code", icmpp_code, 0); rb_define_method(cICMPPacket, "icmp_cksum", icmpp_cksum, 0); klass = rb_define_class_under(mPcap, "ICMPEchoReply", cICMPPacket); icmp_types[ICMP_ECHOREPLY].klass = klass; rb_define_method(klass, "icmp_id", icmpp_id, 0); rb_define_method(klass, "icmp_seq", icmpp_seq, 0); rb_define_method(klass, "icmp_seqle", icmpp_seqle, 0); rb_define_method(klass, "icmp_data", icmpp_data, 0); klass = rb_define_class_under(mPcap, "ICMPUnreach", cICMPPacket); icmp_types[ICMP_UNREACH].klass = klass; rb_define_method(klass, "icmp_nextmtu", icmpp_nextmtu, 0); rb_define_method(klass, "icmp_ip", icmpp_ip, 0); klass = rb_define_class_under(mPcap, "ICMPSourceQuench", cICMPPacket); icmp_types[ICMP_SOURCEQUENCH].klass = klass; rb_define_method(klass, "icmp_ip", icmpp_ip, 0); klass = rb_define_class_under(mPcap, "ICMPRedirect", cICMPPacket); icmp_types[ICMP_REDIRECT].klass = klass; rb_define_method(klass, "icmp_gwaddr", icmpp_gwaddr, 0); rb_define_method(klass, "icmp_ip", icmpp_ip, 0); klass = rb_define_class_under(mPcap, "ICMPEcho", cICMPPacket); icmp_types[ICMP_ECHO].klass = klass; rb_define_method(klass, "icmp_id", icmpp_id, 0); rb_define_method(klass, "icmp_seq", icmpp_seq, 0); rb_define_method(klass, "icmp_seqle", icmpp_seqle, 0); rb_define_method(klass, "icmp_data", icmpp_data, 0); klass = rb_define_class_under(mPcap, "ICMPRouterAdvert", cICMPPacket); icmp_types[ICMP_ROUTERADVERT].klass = klass; rb_define_method(klass, "icmp_num_addrs", icmpp_num_addrs, 0); rb_define_method(klass, "icmp_wpa", icmpp_wpa, 0); rb_define_method(klass, "icmp_lifetime", icmpp_lifetime, 0); rb_define_method(klass, "icmp_radv", icmpp_radv, 1); klass = rb_define_class_under(mPcap, "ICMPRouterSolicit", cICMPPacket); icmp_types[ICMP_ROUTERSOLICIT].klass = klass; klass = rb_define_class_under(mPcap, "ICMPTimxceed", cICMPPacket); icmp_types[ICMP_TIMXCEED].klass = klass; rb_define_method(klass, "icmp_ip", icmpp_ip, 0); klass = rb_define_class_under(mPcap, "ICMPParamProb", cICMPPacket); icmp_types[ICMP_PARAMPROB].klass = klass; rb_define_method(klass, "icmp_pptr", icmpp_pptr, 0); rb_define_method(klass, "icmp_ip", icmpp_ip, 0); klass = rb_define_class_under(mPcap, "ICMPTStamp", cICMPPacket); icmp_types[ICMP_TSTAMP].klass = klass; rb_define_method(klass, "icmp_id", icmpp_id, 0); rb_define_method(klass, "icmp_seq", icmpp_seq, 0); rb_define_method(klass, "icmp_otime", icmpp_otime, 0); rb_define_method(klass, "icmp_rtime", icmpp_rtime, 0); rb_define_method(klass, "icmp_ttime", icmpp_ttime, 0); klass = rb_define_class_under(mPcap, "ICMPTStampReply", cICMPPacket); icmp_types[ICMP_TSTAMPREPLY].klass = klass; rb_define_method(klass, "icmp_id", icmpp_id, 0); rb_define_method(klass, "icmp_seq", icmpp_seq, 0); rb_define_method(klass, "icmp_otime", icmpp_otime, 0); rb_define_method(klass, "icmp_rtime", icmpp_rtime, 0); rb_define_method(klass, "icmp_ttime", icmpp_ttime, 0); klass = rb_define_class_under(mPcap, "ICMPIReq", cICMPPacket); icmp_types[ICMP_IREQ].klass = klass; rb_define_method(klass, "icmp_id", icmpp_id, 0); rb_define_method(klass, "icmp_seq", icmpp_seq, 0); klass = rb_define_class_under(mPcap, "ICMPIReqReply", cICMPPacket); icmp_types[ICMP_IREQREPLY].klass = klass; rb_define_method(klass, "icmp_id", icmpp_id, 0); rb_define_method(klass, "icmp_seq", icmpp_seq, 0); klass = rb_define_class_under(mPcap, "ICMPMaskReq", cICMPPacket); icmp_types[ICMP_MASKREQ].klass = klass; rb_define_method(klass, "icmp_id", icmpp_id, 0); rb_define_method(klass, "icmp_seq", icmpp_seq, 0); /*rb_define_method(klass, "icmp_mask", icmpp_mask, 0);*/ klass = rb_define_class_under(mPcap, "ICMPMaskReply", cICMPPacket); icmp_types[ICMP_MASKREPLY].klass = klass; rb_define_method(klass, "icmp_id", icmpp_id, 0); rb_define_method(klass, "icmp_seq", icmpp_seq, 0); /*rb_define_method(klass, "icmp_mask", icmpp_mask, 0);*/ klass = rb_define_class_under(mPcap, "ICMPTRoute", cICMPPacket); icmp_types[ICMP_TROUTE].klass = klass; rb_define_method(klass, "icmp_id", icmpp_id, 0); rb_define_method(klass, "icmp_ohc", icmpp_ohc, 0); rb_define_method(klass, "icmp_rhc", icmpp_rhc, 0); rb_define_method(klass, "icmp_lspeed", icmpp_lspeed, 0); rb_define_method(klass, "icmp_lmtu", icmpp_lmtu, 0); klass = rb_define_class_under(mPcap, "ICMPDomain", cICMPPacket); icmp_types[ICMP_DOMAIN].klass = klass; rb_define_method(klass, "icmp_id", icmpp_id, 0); rb_define_method(klass, "icmp_seq", icmpp_seq, 0); klass = rb_define_class_under(mPcap, "ICMPDomainReply", cICMPPacket); icmp_types[ICMP_DOMAINREPLY].klass = klass; rb_define_method(klass, "icmp_id", icmpp_id, 0); rb_define_method(klass, "icmp_seq", icmpp_seq, 0); rb_define_method(klass, "icmp_ttl", icmpp_ttl, 0); /*rb_define_method(klass, "icmp_names", icmpp_names, 0);*/ }