#include #include #include extern VALUE cLibnet; static VALUE net_s_decode_ipv6(VALUE self, VALUE bytes) { VALUE ip_obj; VALUE str; VALUE payload; struct libnet_ipv6_hdr *ip; u_int8_t ip_v, ip_tc; u_int32_t ip_fl; u_int16_t ip_len; u_int8_t ip_nh; u_int8_t ip_hl; ip_obj = rb_funcall(self, rb_intern("new"), 0); str = StringValue(bytes); if (RSTRING(str)->len < LIBNET_IPV6_H) { rb_raise(rb_eArgError, "string is too small to contain an IPv6 header"); } ip = (struct libnet_ipv6_hdr *)RSTRING(str)->ptr; ip_v = (ip->ip_flags[0] & 0xf0) >> 4; ip_tc = (ip->ip_flags[0] & 0x0f) << 4; ip_tc |= (ip->ip_flags[1] & 0xf0) >> 4; ip_fl = (ip->ip_flags[1] & 0x0f) << 16; ip_fl |= (ip->ip_flags[2]) << 8; ip_fl |= (ip->ip_flags[3]); ip_len = ntohs(ip->ip_len); ip_nh = ip->ip_nh; ip_hl = ip->ip_hl; rb_iv_set(ip_obj, "@version", UINT2NUM(ip_v)); rb_iv_set(ip_obj, "@traffic_class", UINT2NUM(ip_tc)); rb_iv_set(ip_obj, "@flow_label", ULONG2NUM(ip_fl)); rb_iv_set(ip_obj, "@length", UINT2NUM(ip_len)); rb_iv_set(ip_obj, "@next_header", UINT2NUM(ip_nh)); rb_iv_set(ip_obj, "@hop_limit", UINT2NUM(ip_hl)); rb_iv_set(ip_obj, "@src_ip", rb_str_new((u_int8_t *)&ip->ip_src, sizeof(ip->ip_src))); rb_iv_set(ip_obj, "@dst_ip", rb_str_new((u_int8_t *)&ip->ip_dst, sizeof(ip->ip_dst))); if (RSTRING(str)->len >= LIBNET_IPV6_H + ip_len) { payload = rb_str_new(RSTRING(str)->ptr + LIBNET_IPV6_H, ip_len); } else { payload = Qnil; } rb_iv_set(ip_obj, "@payload", payload); return ip_obj; } static VALUE net_build_ipv6(int argc, VALUE *argv, VALUE self) { libnet_t *l; VALUE ipv6, v; u_int8_t tc, nh, hl; u_int16_t len; u_int32_t fl; struct libnet_in6_addr src, dst; u_int8_t *payload = NULL; u_int32_t payload_s = 0; VALUE ptag_obj; libnet_ptag_t ptag = 0; rb_scan_args(argc, argv, "01", &ipv6); Data_Get_Struct(self, libnet_t, l); if (NIL_P(ipv6)) { ipv6 = rb_class_new_instance(0, NULL, rb_const_get(cLibnet, rb_intern("IPv6"))); rb_yield(ipv6); } /* check that all required fields are set */ rb_funcall(ipv6, rb_intern("check_packable"), 0); v = rb_funcall(ipv6, rb_intern("traffic_class"), 0); tc = NUM2UINT(v); v = rb_funcall(ipv6, rb_intern("flow_label"), 0); fl = NUM2ULONG(v); v = rb_funcall(ipv6, rb_intern("length"), 0); len = NUM2ULONG(v); v = rb_funcall(ipv6, rb_intern("next_header"), 0); nh = NUM2ULONG(v); v = rb_funcall(ipv6, rb_intern("hop_limit"), 0); hl = NUM2ULONG(v); v = rb_funcall(ipv6, rb_intern("src_ip"), 0); v = StringValue(v); memcpy(&src, RSTRING(v)->ptr, sizeof(src)); v = rb_funcall(ipv6, rb_intern("dst_ip"), 0); v = StringValue(v); memcpy(&dst, RSTRING(v)->ptr, sizeof(dst)); /* payload is optional */ if ((v = rb_funcall(ipv6, rb_intern("payload"), 0)) != Qnil) { v = StringValue(v); payload = RSTRING(v)->ptr; payload_s = RSTRING(v)->len; } ptag_obj = rb_iv_get(ipv6, "@ptag"); if (!NIL_P(ptag_obj)) { ptag = NUM2LONG(ptag_obj); } ptag = libnet_build_ipv6(tc, fl, len, nh, hl, src, dst, (u_int8_t *)payload, payload_s, l, ptag); if (ptag == -1) { rb_raise(rb_eRuntimeError, libnet_geterror(l)); } rb_iv_set(ipv6, "@ptag", LONG2NUM(ptag)); return ipv6; } void define_ipv6_methods() { VALUE cIPv6 = rb_const_get(cLibnet, rb_intern("IPv6")); rb_define_singleton_method(cIPv6, "decode", net_s_decode_ipv6, 1); rb_define_method(cLibnet, "build_ipv6", net_build_ipv6, -1); }