ext/pcap/udp_packet.c in ruby-pcap-0.7.9 vs ext/pcap/udp_packet.c in ruby-pcap-0.8.0
- old
+ new
@@ -76,21 +76,282 @@
len = MIN(Caplen(pkt, pkt->hdr.layer5_off), UDP_LENGTH(pkt)-8);
return rb_str_new(UDP_DATA(pkt), len);
}
+static VALUE
+udpp_csum_update(self)
+ VALUE self;
+{
+ struct packet_object *pkt;
+ struct ip *ip;
+ struct udphdr *udp;
+ GetPacket(self, pkt);
+ ip = IP_HDR(pkt);
+ udp = UDP_HDR(pkt);
+ unsigned short *ip_src = (void *)&ip->ip_src.s_addr;
+ unsigned short *ip_dst = (void *)&ip->ip_dst.s_addr;
+ long sum = 0;
+ /* save checksum in packet */
+ unsigned short uh_sum = ntohs(udp->uh_sum);
+ unsigned short answer = 0;
+ unsigned short *temp = (unsigned short *)udp;
+ int len = ntohs(ip->ip_len) - ip->ip_hl*4; // length of ip data
+
+ // pseudo header sum
+ sum += ntohs(*(ip_src++));
+ sum += ntohs(*ip_src);
+ sum += ntohs(*(ip_dst++));
+ sum += ntohs(*ip_dst);
+ sum += 17;
+ sum += len;
+ // set checksum to zero and sum
+ udp->uh_sum = 0;
+ while (len > 1){
+ sum += ntohs(*temp++);
+ len -= 2;
+ }
+ if (len)
+ sum += ntohs((unsigned short) *((unsigned char *)temp));
+ while(sum>>16)
+ sum = (sum & 0xFFFF) + (sum >> 16);
+
+ answer = ~sum;
+ if (answer == 0)
+ answer = ~answer;
+ /*
+ * set checkum in packet
+ */
+ udp->uh_sum = htons(answer);
+ /*
+ * no change, return nil
+ */
+ if (answer == uh_sum)
+ return Qnil;
+ /*
+ * return new checkum
+ */
+ return UINT2NUM(answer);
+}
+
+/*
+ Set UDP source port and update checksum
+*/
+static VALUE
+udpp_sport_set(self, val)
+ VALUE self, val;
+{
+ struct packet_object *pkt;
+ struct udphdr *udp;
+ long sum = 0;
+ GetPacket(self, pkt);
+ udp = UDP_HDR(pkt);
+ /*
+ * https://tools.ietf.org/html/rfc1624
+ * HC' = ~(C + (-m) + m')
+ */
+ sum = ~(~ntohs(udp->uh_sum) - ntohs(udp->uh_sport) + NUM2USHORT(val));
+ while(sum>>16)
+ sum = (sum & 0xFFFF) + (sum >> 16);
+ /*
+ * set desired value and new checksum
+ */
+ udp->uh_sport = htons(NUM2USHORT(val));
+ udp->uh_sum = htons(sum);
+ return val;
+}
+/*
+ Set UDP destination port and update checksum
+*/
+static VALUE
+udpp_dport_set(self, val)
+ VALUE self, val;
+{
+ struct packet_object *pkt;
+ struct udphdr *udp;
+ long sum = 0;
+ GetPacket(self, pkt);
+ udp = UDP_HDR(pkt);
+ /*
+ * https://tools.ietf.org/html/rfc1624
+ * HC' = ~(C + (-m) + m')
+ */
+ sum = ~(~ntohs(udp->uh_sum) - ntohs(udp->uh_dport) + NUM2USHORT(val));
+ while(sum>>16)
+ sum = (sum & 0xFFFF) + (sum >> 16);
+ /*
+ * set desired value and new checksum
+ */
+ udp->uh_dport = htons(NUM2USHORT(val));
+ udp->uh_sum = htons(sum);
+ return val;
+}
+/*
+ * IPv6 Specific methods
+ */
+VALUE cUDPv6Packet;
+
+VALUE
+setup_udpv6_packet(pkt, tl_len)
+ struct packet_object *pkt;
+ int tl_len;
+{
+ VALUE class;
+ DEBUG_PRINT("setup_udpv6_packet");
+ class = cUDPv6Packet;
+ if (tl_len > 8) {
+ int hl = 8;
+ int layer5_len;
+
+ tl_len = MIN(tl_len, UDP_LENGTH(pkt));
+ layer5_len = tl_len - hl;
+ if (layer5_len > 0) {
+ pkt->hdr.layer5_off = pkt->hdr.layer4_off + hl;
+ /* upper layer */
+ }
+ }
+ return class;
+}
+
+static VALUE
+udpp_csumokv6(self)
+ VALUE self;
+{
+ struct packet_object *pkt;
+ struct ip6_hdr *ip;
+ struct udphdr *udp;
+ GetPacket(self, pkt);
+ ip = IPV6_HDR(pkt);
+ udp = UDP_HDR(pkt);
+ unsigned short *ip_src = (void *)&ip->ip6_src.s6_addr;
+ unsigned short *ip_dst = (void *)&ip->ip6_dst.s6_addr;
+ long sum = 0;
+ unsigned short answer = 0;
+ unsigned short *temp = (unsigned short *)udp;
+ int len = ntohs(ip->ip6_plen); // length of ip data
+ unsigned short csum = ntohs(udp->uh_sum); // keep the checksum in packet
+
+ // pseudo header sum
+ int i = 1;
+ for (i = 0; i < 8; i++) {
+ sum += ntohs(*(ip_src));
+ sum += ntohs(*(ip_dst));
+ ip_src++;
+ ip_dst++;
+ }
+ sum += 0x11; // UDP
+ sum += len;
+ // set checksum to zero and sum
+ udp->uh_sum = 0;
+ while (len > 1){
+ sum += ntohs(*temp++);
+ len -= 2;
+ }
+ if (len)
+ sum += ntohs((unsigned short) *((unsigned char *)temp));
+ while(sum>>16)
+ sum = (sum & 0xFFFF) + (sum >> 16);
+ answer = ~sum;
+ if (answer == 0)
+ answer = ~answer;
+ udp->uh_sum = htons(csum); //restore the checkum in packet
+ if (DEBUG_CHECKSUM)
+ printf("UDP csum in packet:%d should be %d\n", csum, answer);
+ if (answer == csum)
+ return Qtrue;
+ return Qfalse;
+}
+
+static VALUE
+udpp_csumok(self)
+ VALUE self;
+{
+ struct packet_object *pkt;
+ struct ip *ip;
+ struct udphdr *udp;
+ GetPacket(self, pkt);
+ ip = IP_HDR(pkt);
+ udp = UDP_HDR(pkt);
+ unsigned short *ip_src = (void *)&ip->ip_src.s_addr;
+ unsigned short *ip_dst = (void *)&ip->ip_dst.s_addr;
+ long sum = 0;
+ unsigned short answer = 0;
+ unsigned short *temp = (unsigned short *)udp;
+ int len = ntohs(ip->ip_len) - ip->ip_hl*4; // length of ip data
+ int csum = ntohs(udp->uh_sum); // keep the checksum in packet
+
+ // pseudo header sum
+ sum += ntohs(*(ip_src++));
+ sum += ntohs(*ip_src);
+ sum += ntohs(*(ip_dst++));
+ sum += ntohs(*ip_dst);
+ sum += 17;
+ sum += len;
+ // set checksum to zero and sum
+ udp->uh_sum = 0;
+ while (len > 1){
+ sum += ntohs(*temp++);
+ len -= 2;
+ }
+ if (len)
+ sum += ntohs((unsigned short) *((unsigned char *)temp));
+ while(sum>>16)
+ sum = (sum & 0xFFFF) + (sum >> 16);
+
+ answer = ~sum;
+ if (answer == 0)
+ answer = ~answer;
+ udp->uh_sum = csum; //restore the checkum in packet
+ if (DEBUG_CHECKSUM)
+ printf("UDP csum in packet:%d should be %d\n", csum, answer);
+ if (answer == csum)
+ return Qtrue;
+ return Qfalse;
+}
+static VALUE
+udpp_truncated(self)
+ VALUE self;
+{
+ struct packet_object *pkt;
+ struct ip *ip;
+ struct udphdr *udp;
+ GetPacket(self, pkt);
+ ip = IP_HDR(pkt);
+ udp = UDP_HDR(pkt);
+ if IsTruncated(pkt, pkt->hdr.layer3_off, ip->ip_hl * 4 + ntohs(udp->uh_ulen))
+ return Qtrue;
+ return Qfalse;
+}
+
void
Init_udp_packet(void)
{
DEBUG_PRINT("Init_udp_packet");
/* define class UdpPacket */
cUDPPacket = rb_define_class_under(mPcap, "UDPPacket", cIPPacket);
-
+ cUDPv6Packet = rb_define_class_under(mPcap, "UDPv6Packet", cIPv6Packet);
+ /* define methods under IPv4 */
rb_define_method(cUDPPacket, "udp_sport", udpp_sport, 0);
+ rb_define_method(cUDPPacket, "udp_sport=", udpp_sport_set, 1);
rb_define_method(cUDPPacket, "sport", udpp_sport, 0);
+ rb_define_method(cUDPPacket, "sport=", udpp_sport_set, 1);
rb_define_method(cUDPPacket, "udp_dport", udpp_dport, 0);
+ rb_define_method(cUDPPacket, "udp_dport=", udpp_dport_set, 1);
rb_define_method(cUDPPacket, "dport", udpp_dport, 0);
+ rb_define_method(cUDPPacket, "dport=", udpp_dport_set, 1);
rb_define_method(cUDPPacket, "udp_len", udpp_len, 0);
rb_define_method(cUDPPacket, "udp_sum", udpp_sum, 0);
rb_define_method(cUDPPacket, "udp_data", udpp_data, 0);
+ rb_define_method(cUDPPacket, "udp_csum_ok?", udpp_csumok, 0);
+ rb_define_method(cUDPPacket, "udp_truncated?", udpp_truncated, 0);
+ rb_define_method(cUDPPacket, "udp_csum_update!", udpp_csum_update, 0);
+ /* define methods under IPv6 */
+ rb_define_method(cUDPv6Packet, "udp_sport", udpp_sport, 0);
+ rb_define_method(cUDPv6Packet, "sport", udpp_sport, 0);
+ rb_define_method(cUDPv6Packet, "udp_dport", udpp_dport, 0);
+ rb_define_method(cUDPv6Packet, "dport", udpp_dport, 0);
+ rb_define_method(cUDPv6Packet, "udp_len", udpp_len, 0);
+ rb_define_method(cUDPv6Packet, "udp_sum", udpp_sum, 0);
+ rb_define_method(cUDPv6Packet, "udp_data", udpp_data, 0);
+ rb_define_method(cUDPv6Packet, "udp_csum_ok?", udpp_csumokv6, 0);
}