static void ipv4(struct pkt_buff *pkt) { uint16_t csum, frag_off, h_tot_len; char src_ip[INET_ADDRSTRLEN]; char dst_ip[INET_ADDRSTRLEN]; struct ipv4hdr *ip = (struct ipv4hdr *) pkt_pull(pkt, sizeof(*ip)); uint8_t *opt, *trailer; unsigned int trailer_len = 0; ssize_t opts_len, opt_len; struct sockaddr_in sas, sad; const char *city, *region, *country; if (!ip) return; frag_off = ntohs(ip->h_frag_off); h_tot_len = ntohs(ip->h_tot_len); csum = calc_csum(ip, ip->h_ihl * 4, 0); inet_ntop(AF_INET, &ip->h_saddr, src_ip, sizeof(src_ip)); inet_ntop(AF_INET, &ip->h_daddr, dst_ip, sizeof(dst_ip)); if ((pkt_len(pkt) + sizeof(*ip)) > h_tot_len) { trailer_len = pkt_len(pkt) + sizeof(*ip) - h_tot_len; trailer = pkt->data + h_tot_len + trailer_len; } if (trailer_len) { tprintf(" [ Eth trailer "); while (trailer_len--) { tprintf("%x", *(trailer - trailer_len)); } tprintf(" ]\n"); } tprintf(" [ IPv4 "); tprintf("Addr (%s => %s), ", src_ip, dst_ip); tprintf("Proto (%u), ", ip->h_protocol); tprintf("TTL (%u), ", ip->h_ttl); tprintf("TOS (%u), ", ip->h_tos); tprintf("Ver (%u), ", ip->h_version); tprintf("IHL (%u), ", ip->h_ihl); tprintf("Tlen (%u), ", ntohs(ip->h_tot_len)); tprintf("ID (%u), ", ntohs(ip->h_id)); tprintf("Res (%u), NoFrag (%u), MoreFrag (%u), FragOff (%u), ", FRAG_OFF_RESERVED_FLAG(frag_off) ? 1 : 0, FRAG_OFF_NO_FRAGMENT_FLAG(frag_off) ? 1 : 0, FRAG_OFF_MORE_FRAGMENT_FLAG(frag_off) ? 1 : 0, FRAG_OFF_FRAGMENT_OFFSET(frag_off)); tprintf("CSum (0x%.4x) is %s", ntohs(ip->h_check), csum ? colorize_start_full(black, red) "bogus (!)" colorize_end() : "ok"); if (csum) tprintf("%s should be 0x%.4x%s", colorize_start_full(black, red), csum_expected(ip->h_check, csum), colorize_end()); tprintf(" ]\n"); memset(&sas, 0, sizeof(sas)); sas.sin_family = PF_INET; sas.sin_addr.s_addr = ip->h_saddr; memset(&sad, 0, sizeof(sad)); sad.sin_family = PF_INET; sad.sin_addr.s_addr = ip->h_daddr; if (geoip_working()) { tprintf("\t[ Geo ("); if ((country = geoip4_country_name(sas))) { tprintf("%s", country); if ((region = geoip4_region_name(sas))) tprintf(" / %s", region); if ((city = geoip4_city_name(sas))) tprintf(" / %s", city); } else { tprintf("local"); } tprintf(" => "); if ((country = geoip4_country_name(sad))) { tprintf("%s", country); if ((region = geoip4_region_name(sad))) tprintf(" / %s", region); if ((city = geoip4_city_name(sad))) tprintf(" / %s", city); } else { tprintf("local"); } tprintf(") ]\n"); } opts_len = max((uint8_t) ip->h_ihl, sizeof(*ip) / sizeof(uint32_t)) * sizeof(uint32_t) - sizeof(*ip); for (opt = pkt_pull(pkt, opts_len); opt && opts_len > 0; opt++) { tprintf(" [ Option Copied (%u), Class (%u), Number (%u)", IP_OPT_COPIED_FLAG(*opt) ? 1 : 0, IP_OPT_CLASS(*opt), IP_OPT_NUMBER(*opt)); switch (*opt) { case IP_OPT_EOOL: case IP_OPT_NOP: tprintf(" ]\n"); opts_len--; break; default: /* * Assuming that EOOL and NOP are the only single-byte * options, treat all other options as variable in * length with a minimum of 2. * * TODO: option length might be incorrect in malformed packets, * check and handle that */ opt_len = *(++opt); if (opt_len > opts_len) { tprintf(", Len (%zd, invalid) ]\n", opt_len); goto out; } else tprintf(", Len (%zd) ]\n", opt_len); opts_len -= opt_len; tprintf(" [ Data hex "); for (opt_len -= 2; opt_len > 0; opt_len--) tprintf(" %.2x", *(++opt)); tprintf(" ]\n"); break; } } out: /* cut off everything that is not part of IPv4 payload */ /* XXX there could still be an Ethernet trailer included or others */ pkt_trim(pkt, pkt_len(pkt) - min(pkt_len(pkt), (ntohs(ip->h_tot_len) - ip->h_ihl * sizeof(uint32_t)))); pkt_set_proto(pkt, ð_lay3, ip->h_protocol); }
static int test_ip_opt(void) { struct pkt *pkt; struct timeval tv; struct ip_opt opts[IP_OPT_MAX]; int i, len, max; printf("ip-opt: "); fflush(stdout); memset(&opts, 0, sizeof(opts)); max = 0; opts[max].opt_type = IP_OPT_SEC; opts[max].opt_len = IP_OPT_LEN + 9; max++; opts[max].opt_type = IP_OPT_LSRR; opts[max].opt_len = IP_OPT_LEN + 1 + 4; opts[max].opt_data.rr.ptr = 8; opts[max].opt_data.rr.iplist[0] = ping->pkt_ip->ip_src; max++; opts[max].opt_type = IP_OPT_TS; opts[max].opt_len = IP_OPT_LEN + 1 + 1 + 4; opts[max].opt_data.ts.ptr = 5; opts[max].opt_data.ts.flg = IP_OPT_TS_TSONLY; max++; opts[max].opt_type = IP_OPT_ESEC; opts[max].opt_len = IP_OPT_LEN; max++; opts[max].opt_type = IP_OPT_CIPSO; opts[max].opt_len = IP_OPT_LEN; max++; opts[max].opt_type = IP_OPT_RR; opts[max].opt_len = IP_OPT_LEN + 1 + 4; opts[max].opt_data.rr.ptr = 4; max++; opts[max].opt_type = IP_OPT_SATID; opts[max].opt_len = IP_OPT_LEN + 2; max++; opts[max].opt_type = IP_OPT_SSRR; opts[max].opt_len = IP_OPT_LEN + 1 + 4; opts[max].opt_data.rr.ptr = 8; opts[max].opt_data.rr.iplist[0] = ping->pkt_ip->ip_src; max++; pcap_filter(ctx.pcap, "icmp and src %s and dst %s", addr_ntoa(&ctx.dst), addr_ntoa(&ctx.src)); ping->pkt_icmp_msg->echo.icmp_id = rand_uint16(ctx.rnd); for (i = 0; i < max; i++) { pkt = pkt_dup(ping); pkt->pkt_ip->ip_id = rand_uint16(ctx.rnd); pkt->pkt_icmp_msg->echo.icmp_seq = opts[i].opt_type; len = ip_add_option(pkt->pkt_ip, PKT_BUF_LEN - ETH_HDR_LEN + IP_HDR_LEN, IP_PROTO_IP, &opts[i], opts[i].opt_len); pkt->pkt_end += len; ip_checksum(pkt->pkt_ip, pkt->pkt_end - pkt->pkt_eth_data); send_pkt(pkt); } i = 0; for (tv = read_tv; (pkt = recv_pkt(&tv)) != NULL; tv = read_tv) { if (pkt->pkt_icmp->icmp_type == ICMP_ECHOREPLY && pkt->pkt_icmp_msg->echo.icmp_id == ping->pkt_icmp_msg->echo.icmp_id) { i = IP_OPT_NUMBER(pkt->pkt_icmp_msg->echo.icmp_seq); printf("%s ", optnames[i]); } } printf("%s\n", i ? "" : "none"); return (0); }