static int test_ping(void) { struct pkt *pkt; struct timeval tv; printf("ping: "); fflush(stdout); ping->pkt_icmp_msg->echo.icmp_id = rand_uint16(ctx.rnd); pkt = pkt_dup(ping); pkt->pkt_ip->ip_id = rand_uint16(ctx.rnd); ip_checksum(pkt->pkt_ip, pkt->pkt_end - pkt->pkt_eth_data); pcap_filter(ctx.pcap, "icmp[0] = 0 and src %s and dst %s", addr_ntoa(&ctx.dst), addr_ntoa(&ctx.src)); send_pkt(pkt); for (tv = read_tv; (pkt = recv_pkt(&tv)) != NULL; tv = read_tv) { if (memcmp(&pkt->pkt_icmp_msg->echo, &ping->pkt_icmp_msg->echo, 8) == 0) break; } printf("%s\n", pkt ? timeval_ntoa(&tv) : "no reply"); return (0); }
static int pcap_read_haiku(pcap_t* handle, int maxPackets, pcap_handler callback, u_char* userdata) { // Receive a single packet struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv; u_char* buffer = (u_char*)handle->buffer + handle->offset; struct sockaddr_dl from; ssize_t bytesReceived; do { if (handle->break_loop) { // Clear the break loop flag, and return -2 to indicate our // reasoning handle->break_loop = 0; return -2; } socklen_t fromLength = sizeof(from); bytesReceived = recvfrom(handle->fd, buffer, handle->bufsize, MSG_TRUNC, (struct sockaddr*)&from, &fromLength); } while (bytesReceived < 0 && errno == B_INTERRUPTED); if (bytesReceived < 0) { if (errno == B_WOULD_BLOCK) { // there is no packet for us return 0; } snprintf(handle->errbuf, sizeof(handle->errbuf), "recvfrom: %s", strerror(errno)); return -1; } int32 captureLength = bytesReceived; if (captureLength > handle->snapshot) captureLength = handle->snapshot; // run the packet filter if (handle->fcode.bf_insns) { if (pcap_filter(handle->fcode.bf_insns, buffer, bytesReceived, captureLength) == 0) { // packet got rejected return 0; } } // fill in pcap_header pcap_pkthdr header; header.caplen = captureLength; header.len = bytesReceived; header.ts.tv_usec = system_time() % 1000000; header.ts.tv_sec = system_time() / 1000000; // TODO: get timing from packet!!! /* Call the user supplied callback function */ callback(userdata, &header, buffer); return 1; }
static int test_frag(char *overlap, int drop) { struct timeval tv, save_tv = read_tv; struct pkt *pkt; struct icmp_msg_echo *echo; char *frag_argv[4]; if (overlap != NULL) printf("frag-%s: ", overlap); else if (drop) printf("frag-timeout (please wait): "); else printf("frag: "); fflush(stdout); ping->pkt_ip->ip_id = rand_uint16(ctx.rnd); ping->pkt_icmp_msg->echo.icmp_id = rand_uint16(ctx.rnd); pkt = pkt_dup(ping); ip_checksum(pkt->pkt_ip, pkt->pkt_end - pkt->pkt_eth_data); TAILQ_INSERT_TAIL(&ctx.pktq, pkt, pkt_next); frag_argv[0] = "ip_frag"; frag_argv[1] = "8"; frag_argv[2] = overlap; frag_argv[3] = NULL; mod_ip_frag.open(overlap ? 3 : 2, frag_argv, NULL); mod_ip_frag.apply(NULL, &ctx.pktq, NULL); if (drop) { pkt = TAILQ_LAST(&ctx.pktq, pktq); TAILQ_REMOVE(&ctx.pktq, pkt, pkt_next); pkt_free(pkt); save_tv.tv_sec = FRAG_TIMEOUT; } pcap_filter(ctx.pcap, "icmp[0] = %d and src %s and dst %s", drop ? 11 : 0, addr_ntoa(&ctx.dst), addr_ntoa(&ctx.src)); send_pktq(&ctx.pktq); for (tv = save_tv; (pkt = recv_pkt(&tv)) != NULL; tv = save_tv) { if (drop) { echo = (struct icmp_msg_echo *) (pkt->pkt_icmp_msg->timexceed.icmp_ip + IP_HDR_LEN + ICMP_HDR_LEN); } else { echo = &pkt->pkt_icmp_msg->echo; } if (echo->icmp_id == ping->pkt_icmp_msg->echo.icmp_id) break; } printf("%s\n", pkt ? timeval_ntoa(&tv) : "no reply"); return (0); }
static int test_ip_tracert(void) { struct timeval tv; struct hop hops[IP_TTL_DEFAULT]; struct pkt *pkt; struct icmp_msg_echo *echo; int i, hopcnt, max_ttl; printf("ip-tracert: "); fflush(stdout); pcap_filter(ctx.pcap, "icmp[0] = 0 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); pkt = pkt_dup(ping); pkt->pkt_ip->ip_id = rand_uint16(ctx.rnd); ip_checksum(pkt->pkt_ip, pkt->pkt_end - pkt->pkt_eth_data); send_pkt(pkt); tv = read_tv; if ((pkt = recv_pkt(&tv)) == NULL) { printf("no reply\n"); return (0); } /* XXX - guess remote stack's starting TTL */ for (i = 2; pkt->pkt_ip->ip_ttl > i; i <<= 1) ; if ((max_ttl = i - pkt->pkt_ip->ip_ttl + 1) > IP_TTL_DEFAULT) max_ttl = IP_TTL_DEFAULT; printf("%s, %d hops max\n", ip_ntoa(&ping->pkt_ip->ip_dst), max_ttl); pcap_filter(ctx.pcap, "icmp and dst %s", addr_ntoa(&ctx.src)); for (i = 1; i < max_ttl + 1; i++) { pkt = pkt_dup(ping); pkt->pkt_ip->ip_id = rand_uint16(ctx.rnd); pkt->pkt_ip->ip_ttl = i; pkt->pkt_icmp_msg->echo.icmp_seq = htons(i); ip_checksum(pkt->pkt_ip, pkt->pkt_end - pkt->pkt_eth_data); send_pkt(pkt); usleep(42); /* XXX */ } memset(&hops, 0, sizeof(hops)); hopcnt = 0; for (tv = read_tv; (pkt = recv_pkt(&tv)) != NULL; tv = read_tv) { if ((pkt->pkt_icmp->icmp_type == ICMP_TIMEXCEED || pkt->pkt_icmp->icmp_type == ICMP_UNREACH) && pkt->pkt_end - pkt->pkt_eth_data >= (IP_HDR_LEN + ICMP_LEN_MIN) * 2) { echo = (struct icmp_msg_echo *) (pkt->pkt_icmp_msg->timexceed.icmp_ip + IP_HDR_LEN + ICMP_HDR_LEN); } else if (pkt->pkt_icmp->icmp_type == ICMP_ECHOREPLY) { echo = &pkt->pkt_icmp_msg->echo; } else continue; if (echo->icmp_id != ping->pkt_icmp_msg->echo.icmp_id) continue; i = ntohs(echo->icmp_seq); addr_pack(&hops[i].addr, ADDR_TYPE_IP, IP_ADDR_BITS, &pkt->pkt_ip->ip_src, IP_ADDR_LEN); memcpy(&hops[i].icmp, pkt->pkt_icmp, ICMP_HDR_LEN); hops[i].ttl = pkt->pkt_ip->ip_ttl; hopcnt++; if (pkt->pkt_ip->ip_src == ping->pkt_ip->ip_dst) break; } for (i = 1; i < hopcnt + 1; i++) { if (hops[i].addr.addr_type == ADDR_TYPE_IP) { printf("%2d %s (%d)\n", i, addr_ntoa(&hops[i].addr), hops[i].ttl); } else printf("%2d *\n", i); } return (0); }
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); }
static int netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { struct pcap_netfilter *handlep = handle->priv; register u_char *bp, *ep; int count = 0; ssize_t len; /* * Has "pcap_breakloop()" been called? */ if (handle->break_loop) { /* * Yes - clear the flag that indicates that it * has, and return PCAP_ERROR_BREAK to indicate * that we were told to break out of the loop. */ handle->break_loop = 0; return PCAP_ERROR_BREAK; } len = handle->cc; if (len == 0) { /* * The buffer is empty; refill it. * * We ignore EINTR, as that might just be due to a signal * being delivered - if the signal should interrupt the * loop, the signal handler should call pcap_breakloop() * to set handle->break_loop (we ignore it on other * platforms as well). */ do { len = recv(handle->fd, handle->buffer, handle->bufsize, 0); if (handle->break_loop) { handle->break_loop = 0; return PCAP_ERROR_BREAK; } if (errno == ENOBUFS) handlep->packets_nobufs++; } while ((len == -1) && (errno == EINTR || errno == ENOBUFS)); if (len < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't receive packet"); return PCAP_ERROR; } bp = (unsigned char *)handle->buffer; } else bp = handle->bp; ep = bp + len; while (bp < ep) { const struct nlmsghdr *nlh = (const struct nlmsghdr *) bp; uint32_t msg_len; nftype_t type = OTHER; /* * Has "pcap_breakloop()" been called? * If so, return immediately - if we haven't read any * packets, clear the flag and return PCAP_ERROR_BREAK * to indicate that we were told to break out of the loop, * otherwise leave the flag set, so that the *next* call * will break out of the loop without having read any * packets, and return the number of packets we've * processed so far. */ if (handle->break_loop) { handle->bp = bp; handle->cc = (int)(ep - bp); if (count == 0) { handle->break_loop = 0; return PCAP_ERROR_BREAK; } else return count; } if (ep - bp < NLMSG_SPACE(0)) { /* * There's less than one netlink message left * in the buffer. Give up. */ break; } if (nlh->nlmsg_len < sizeof(struct nlmsghdr) || (u_int)len < nlh->nlmsg_len) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Message truncated: (got: %zd) (nlmsg_len: %u)", len, nlh->nlmsg_len); return -1; } if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_ULOG && NFNL_MSG_TYPE(nlh->nlmsg_type) == NFULNL_MSG_PACKET) type = NFLOG; else if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_QUEUE && NFNL_MSG_TYPE(nlh->nlmsg_type) == NFQNL_MSG_PACKET) type = NFQUEUE; if (type != OTHER) { const unsigned char *payload = NULL; struct pcap_pkthdr pkth; const struct nfgenmsg *nfg = NULL; int id = 0; if (handle->linktype != DLT_NFLOG) { const struct nfattr *payload_attr = NULL; if (nlh->nlmsg_len < HDR_LENGTH) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Malformed message: (nlmsg_len: %u)", nlh->nlmsg_len); return -1; } nfg = NLMSG_DATA(nlh); if (nlh->nlmsg_len > HDR_LENGTH) { struct nfattr *attr = NFM_NFA(nfg); int attr_len = nlh->nlmsg_len - NLMSG_ALIGN(HDR_LENGTH); while (NFA_OK(attr, attr_len)) { if (type == NFQUEUE) { switch (NFA_TYPE(attr)) { case NFQA_PACKET_HDR: { const struct nfqnl_msg_packet_hdr *pkt_hdr = (const struct nfqnl_msg_packet_hdr *) NFA_DATA(attr); id = ntohl(pkt_hdr->packet_id); break; } case NFQA_PAYLOAD: payload_attr = attr; break; } } else if (type == NFLOG) { switch (NFA_TYPE(attr)) { case NFULA_PAYLOAD: payload_attr = attr; break; } } attr = NFA_NEXT(attr, attr_len); } } if (payload_attr) { payload = NFA_DATA(payload_attr); pkth.len = pkth.caplen = NFA_PAYLOAD(payload_attr); } } else { payload = NLMSG_DATA(nlh); pkth.caplen = pkth.len = nlh->nlmsg_len-NLMSG_ALIGN(sizeof(struct nlmsghdr)); } if (payload) { /* pkth.caplen = min (payload_len, handle->snapshot); */ gettimeofday(&pkth.ts, NULL); if (handle->fcode.bf_insns == NULL || pcap_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen)) { handlep->packets_read++; callback(user, &pkth, payload); count++; } } if (type == NFQUEUE) { /* XXX, possible responses: NF_DROP, NF_ACCEPT, NF_STOLEN, NF_QUEUE, NF_REPEAT, NF_STOP */ /* if type == NFQUEUE, handle->linktype is always != DLT_NFLOG, so nfg is always initialized to NLMSG_DATA(nlh). */ if (nfg != NULL) nfqueue_send_verdict(handle, ntohs(nfg->res_id), id, NF_ACCEPT); } } msg_len = NLMSG_ALIGN(nlh->nlmsg_len); /* * If the message length would run past the end of the * buffer, truncate it to the remaining space in the * buffer. */ if (msg_len > ep - bp) msg_len = (uint32_t)(ep - bp); bp += msg_len; if (count >= max_packets && !PACKET_COUNT_IS_UNLIMITED(max_packets)) { handle->bp = bp; handle->cc = (int)(ep - bp); if (handle->cc < 0) handle->cc = 0; return count; } } handle->cc = 0; return count; }
static int rdmasniff_read(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { struct pcap_rdmasniff *priv = handle->priv; struct ibv_cq *ev_cq; void *ev_ctx; struct ibv_wc wc; struct pcap_pkthdr pkth; u_char *pktd; int count = 0; if (!priv->cq_event) { while (ibv_get_cq_event(priv->channel, &ev_cq, &ev_ctx) < 0) { if (errno != EINTR) { return PCAP_ERROR; } if (handle->break_loop) { handle->break_loop = 0; return PCAP_ERROR_BREAK; } } ibv_ack_cq_events(priv->cq, 1); ibv_req_notify_cq(priv->cq, 0); priv->cq_event = 1; } while (count < max_packets || PACKET_COUNT_IS_UNLIMITED(max_packets)) { if (ibv_poll_cq(priv->cq, 1, &wc) != 1) { priv->cq_event = 0; break; } if (wc.status != IBV_WC_SUCCESS) { fprintf(stderr, "failed WC wr_id %lld status %d/%s\n", (unsigned long long) wc.wr_id, wc.status, ibv_wc_status_str(wc.status)); continue; } pkth.len = wc.byte_len; pkth.caplen = min(pkth.len, (u_int)handle->snapshot); gettimeofday(&pkth.ts, NULL); pktd = (u_char *) handle->buffer + wc.wr_id * RDMASNIFF_RECEIVE_SIZE; if (handle->fcode.bf_insns == NULL || pcap_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) { callback(user, &pkth, pktd); ++priv->packets_recv; ++count; } rdmasniff_post_recv(handle, wc.wr_id); if (handle->break_loop) { handle->break_loop = 0; return PCAP_ERROR_BREAK; } } return count; }