📄 udp_scan.c
字号:
last_reply = now; write_port(add_port(test_portno)); } } while (ports_busy && (ports_busy >= hard_limit || ports_busy >= probes_done || ports_busy >= soft_limit));}/* receive_answers - receive reactions to probes */receive_answers(){ fd_set read_mask; struct timeval waitsome; double delay; int answers; /* * The timeout is less than the inter-reply arrival time or we would not * be able to increase the load. */ delay = (2 * avg_rtt < avg_irt ? avg_irt / 3 : avg_rtt / (1 + ports_busy * 4)); waitsome.tv_sec = delay; waitsome.tv_usec = (delay - waitsome.tv_sec) * 1000000; read_mask = icmp_sock_mask; if ((answers = select(icmp_sock + 1, &read_mask, (fd_set *) 0, (fd_set *) 0, &waitsome)) < 0) error("select: %m"); gettimeofday(&now, (struct timezone *) 0); /* * For each answer that we receive without retransmissions, update the * average roundtrip time. */ if (answers > 0) { if (FD_ISSET(icmp_sock, &read_mask)) receive_icmp(icmp_sock); } return (answers);}/* receive_icmp - receive and decode ICMP message */receive_icmp(sock)int sock;{ union { char chars[BUFSIZ]; struct ip ip; } buf; int data_len; int hdr_len; struct ip *ip; struct icmp *icmp; struct udphdr *udp; struct port_info *sp; if ((data_len = recv(sock, (char *) &buf, sizeof(buf), 0)) < 0) { error("error: recv: %m"); return; } /* * Extract the IP header. */ ip = &buf.ip; if (ip->ip_p != IPPROTO_ICMP) { error("error: not ICMP proto (%d)", ip->ip_p); return; } /* * Extract the IP payload. */ hdr_len = ip->ip_hl << 2; if (data_len - hdr_len < ICMP_MINLEN) { remark("short ICMP packet (%d bytes)", data_len); return; } icmp = (struct icmp *) ((char *) ip + hdr_len); data_len -= hdr_len; if (icmp->icmp_type != ICMP_UNREACH) return; /* * Extract the offending IP header. */ if (data_len < offsetof(struct icmp, icmp_ip) + sizeof(icmp->icmp_ip)) { remark("short IP header in ICMP"); return; } ip = &(icmp->icmp_ip); if (ip->ip_p != IPPROTO_UDP) return; if (ip->ip_dst.s_addr != dst.sin_addr.s_addr) return; /* * Extract the offending UDP header. */ hdr_len = ip->ip_hl << 2; udp = (struct udphdr *) ((char *) ip + hdr_len); data_len -= hdr_len; if (data_len < sizeof(struct udphdr)) { remark("short UDP header in ICMP"); return; } /* * Process ICMP subcodes. */ switch (icmp->icmp_code) { case ICMP_UNREACH_NET: error("error: network unreachable"); /* NOTREACHED */ case ICMP_UNREACH_HOST: if (sp = find_port_info(ntohs(udp->uh_dport))) process_reply(sp, EHOSTUNREACH); break; case ICMP_UNREACH_PROTOCOL: error("error: protocol unreachable"); /* NOTREACHED */ case ICMP_UNREACH_PORT: if (sp = find_port_info(ntohs(udp->uh_dport))) process_reply(sp, ECONNREFUSED); break; }}/* process_reply - process reply */process_reply(sp, err)struct port_info *sp;int err;{ double age = sock_age(sp); int pkts = sp->pkts; double irt = time_since(last_reply); /* * Don't believe everything. */ if (age > 5) { age = 5; } else if (age < 0) { age = 1; } if (irt > 5) { irt = 5; } else if (irt < 0) { irt = 1; } /* * We jump some hoops for calibration purposes. First we estimate the * round-trip time: we use this to decide when to retransmit when network * transit time dominates. * * Next thing to do is to estimate the inter-reply time, in case the sender * has a "dead time" for ICMP replies; I have seen this happen with some * Cisco routers and with Solaris 2.4. The first reply will come fast; * subsequent probes will be ignored for a period of up to one second. * When this happens the retransmission period should be based on the * inter-reply time and not on the average round-trip time. */ last_reply = now; replies++; if (pkts == 1) avg_rtt = (avg_rtt == 0 ? age : /* adopt initial rtt */ average(age, avg_rtt)); /* normal processing */ avg_irt = (avg_irt == 0 ? 1 : /* prepare for irt * calibration */ avg_irt == 1 ? irt : /* adopt initial irt */ average(irt, avg_irt)); /* normal processing */ avg_pkts = average((double) pkts, avg_pkts); if (verbose) printf("%d:age %.3f irt %.3f pkt %d ports %2d soft %2d done %2d avrtt %.3f avpkt %.3f avirt %.3f\n", sp->port, age, irt, pkts, ports_busy, soft_limit, probes_done, avg_rtt, avg_pkts, avg_irt); report_and_drop_port(sp, err);}/* report_and_drop_port - report what we know about this service */report_and_drop_port(sp, err)struct port_info *sp;int err;{ struct servent *se; if (probes_done == 0) { if (err == 0) error("are we talking to a dead host or network?"); } else if (show_all || want_err == err || (want_err < 0 && want_err != ~err)) { printf("%d:%s:", sp->port, (se = getservbyport(htons(sp->port), "udp")) ? se->s_name : "UNKNOWN"); if (err && show_all) printf("%s", strerror(err)); printf("\n"); fflush(stdout); } drop_port(sp);}/* average - quick-rise, slow-decay moving average */double average(new, old)double new;double old;{ if (new > old) { /* quick rise */ return ((new + old) / 2); } else { /* slow decay */ return (0.1 * new + 0.9 * old); }}/* add_port - say this port is being probed */struct port_info *add_port(port)int port;{ struct port_info *sp = (struct port_info *) ring_succ(&dead_ports); ring_detach((RING *) sp); sp->port = port; sp->pkts = 0; ports_busy++; ring_append(&active_ports, (RING *) sp); return (sp);}/* write_port - write to port, update statistics */write_port(sp)struct port_info *sp;{ char ch = 0; ring_detach((RING *) sp); dst.sin_port = htons(sp->port); sp->last_probe = now; sendto(send_sock, &ch, 1, 0, (struct sockaddr *) & dst, sizeof(dst)); probes_sent++; sp->pkts++; ring_prepend(&active_ports, (RING *) sp); /* * Reduce the sending window when the first retransmission happens. Back * off when retransmissions dominate. Occasional retransmissons will keep * the load unchanged. */ if (sp->pkts > 1) { replies--; if (soft_limit > hard_limit) { soft_limit = (ports_busy + 1) / 2; } else if (replies < 0 && avg_irt) { soft_limit = 0.5 + 0.5 * (soft_limit + avg_rtt / avg_irt); replies = soft_limit / 2; } }}/* drop_port - release port info, update statistics */drop_port(sp)struct port_info *sp;{ ports_busy--; probes_done++; ring_detach((RING *) sp); ring_append(&dead_ports, (RING *) sp); /* * Increase the load when a sufficient number of probes succeeded. * Occasional retransmissons will keep the load unchanged. */ if (replies > soft_limit) { replies = soft_limit / 2; if (soft_limit < hard_limit) soft_limit++; }}/* init_port_info - initialize port info pool */init_port_info(){ struct port_info *sp; port_info = (struct port_info *) mymalloc(hard_limit * sizeof(*port_info)); ring_init(&active_ports); ring_init(&dead_ports); for (sp = port_info; sp < port_info + hard_limit; sp++) ring_append(&dead_ports, (RING *) sp);}/* find_port_info - lookup port info */struct port_info *find_port_info(port)int port;{ struct port_info *sp; for (sp = (struct port_info *) ring_succ(&active_ports); sp != (struct port_info *) & active_ports; sp = (struct port_info *) ring_succ((RING *) sp)) if (sp->port == port) return (sp); return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -