?? udp_scan.c
字號:
/* * udp-scan - determine available udp services * * Author: Wietse Venema. */#include <sys/types.h>#include <sys/param.h>#include <sys/socket.h>#include <sys/time.h>#include <netinet/in_systm.h>#include <netinet/in.h>#include <netinet/ip.h>#include <netinet/ip_icmp.h>#include <netinet/udp.h>#include <errno.h>#include <netdb.h>#include <stdio.h>#include <string.h>extern int errno;#ifndef __STDC__extern char *strerror();#endifextern char *optarg;extern int optind;#define offsetof(t,m) (size_t)(&(((t *)0)->m))#ifndef FD_SET#include <sys/select.h>#endif#ifndef INADDR_ANY#define INADDR_ANY 0xffffffff#endif#include "lib.h"#define LOAD_LIMIT 100 /* default max nr of open sockets */#define AVG_MARGIN 10 /* safety margin */ /* * In order to protect ourselves against dead hosts, we first probe UDP port * 1. If we do not get an ICMP error (no listener or host unreachable) we * assume this host is dead. If we do get an ICMP error, we have an estimate * of the roundtrip time. The test port can be changed with the -p option. */char *test_port = "1";int test_portno;#define YES 1#define NO 0int verbose = 0; /* default silent mode */int open_file_limit; /* max nr of open files */ /* * We attempt to send as many probes per roundtrip time as network capacity * permits. With UDP we must do our own retransmission and congestion * handling. */int hard_limit = LOAD_LIMIT; /* max nr of open sockets */int soft_limit; /* slowly-moving load limit */struct timeval now; /* global time after select() */int ports_busy; /* number of open sockets */int want_err = 0; /* show reachable/unreachable */int show_all = 0; /* show all ports */ /* * Information about ongoing probes is sorted by time of last transmission. */struct port_info { RING ring; /* round-robin linkage */ struct timeval last_probe; /* time of last probe */ int port; /* port number */ int pkts; /* number of packets sent */};struct port_info *port_info = 0;RING active_ports; /* active sockets list head */RING dead_ports; /* dead sockets list head */struct port_info *find_port_info(); /* retrieve port info */ /* * Performance statistics. These are used to update the transmission window * size depending on transmission error rates. */double avg_irt = 0; /* inter-reply arrival time */double avg_rtt = 0; /* round-trip time */double avg_pkts = 1; /* number of packets sent per reply */int probes_sent = 0; /* probes sent */int probes_done = 0; /* finished probes */int replies; /* number of good single probes */struct timeval last_reply; /* time of last reply */int send_sock; /* send probes here */int icmp_sock; /* read replies here */fd_set icmp_sock_mask; /* select() read mask */static struct sockaddr_in dst; /* * Helpers... */#define time_since(t) (now.tv_sec - t.tv_sec + 1e-6 * (now.tv_usec - t.tv_usec))#define sock_age(sp) time_since(sp->last_probe)double average();struct port_info *add_port();/* main - command-line interface */main(argc, argv)int argc;char *argv[];{ int c; struct protoent *pe; char **ports; struct sockaddr_in src; char *src_port = 0; progname = argv[0]; if (geteuid()) error("This program needs root privileges"); open_file_limit = open_limit(); while ((c = getopt(argc, argv, "al:p:SuUv")) != EOF) { switch (c) { case 'a': show_all = 1; break; case 'l': if ((hard_limit = atoi(optarg)) <= 0) usage("invalid load limit"); break; case 'p': test_port = optarg; break; case 'S': src_port = optarg; break; case 'u': want_err = EHOSTUNREACH; break; case 'U': want_err = ~EHOSTUNREACH; break; case 'v': verbose = 1; break; default: usage((char *) 0); break; } } argc -= (optind - 1); argv += (optind - 1); if (argc < 3) usage("missing argument"); if (hard_limit > open_file_limit - 10) hard_limit = open_file_limit - 10; soft_limit = hard_limit + 1; init_port_info(); if ((pe = getprotobyname("icmp")) == 0) error("icmp: unknown protocol"); if ((icmp_sock = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) error("icmp socket: %m"); FD_ZERO(&icmp_sock_mask); FD_SET(icmp_sock, &icmp_sock_mask); if ((send_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) error("socket: %m"); /* * First do a test probe to see if the host is up, and to establish the * round-trip time. This requires that the test port is not used on the * target host. */ memset((char *) &dst, 0, sizeof(dst)); dst.sin_addr = find_addr(argv[1]); dst.sin_family = AF_INET; if (src_port) { memset((char *) &src, 0, sizeof(src)); src.sin_addr.s_addr = INADDR_ANY; src.sin_port = find_port(src_port, "udp"); src.sin_family = AF_INET; if (bind(send_sock, (struct sockaddr *) & src, sizeof(src)) < 0) error("bind port %s: %m", src_port); } gettimeofday(&now, (struct timezone *) 0); last_reply = now; /* * Calibrate round-trip time and dead time. */ for (;;) { scan_ports(test_port); while (ports_busy > 0) monitor_ports(); if (avg_rtt) break; sleep(1); } scan_ports(test_port); /* * Scan those ports. */ for (ports = argv + 2; *ports; ports++) scan_ports(*ports); /* * All ports probed, wait for replies to trickle back. */ while (ports_busy > 0) monitor_ports(); return (0);}/* usage - explain command syntax */usage(why)char *why;{ if (why) remark(why); error("usage: %s [-apuU] [-l load] [-S src_port] host ports...", progname);}/* scan_ports - scan ranges of ports */scan_ports(service)char *service;{ char *cp; int min_port; int max_port; int port; struct port_info *sp; if (service == test_port) test_portno = atoi(test_port); /* * Translate service argument to range of port numbers. */ if ((cp = strchr(service, '-')) != 0) { *cp++ = 0; min_port = (service[0] ? ntohs(find_port(service, "udp")) : 1); max_port = (cp[0] ? ntohs(find_port(cp, "udp")) : 65535); } else { min_port = max_port = ntohs(find_port(service, "udp")); } /* * Iterate over each port in the given range. Adjust the number of * simultaneous probes to the capacity of the network. */ for (port = min_port; port <= max_port; port++) { sp = add_port(port); write_port(sp); monitor_ports(); }}/* monitor_ports - watch for socket activity */monitor_ports(){ do { struct port_info *sp; /* * When things become quiet, examine the port that we haven't looked * at for the longest period of time. */ receive_answers(); if (ports_busy == 0) return; sp = (struct port_info *) ring_succ(&active_ports); if (sp->pkts > avg_pkts * AVG_MARGIN) { report_and_drop_port(sp, 0); } else /* * Strategy depends on whether transit times dominate (probe * multiple ports in parallel, retransmit when no reply was * received for at least one round-trip period) or by dead time * (probe one port at a time, retransmit when no reply was * received for some fraction of the inter-reply period). */ if (sock_age(sp) > (avg_rtt == 0 ? 1 : 2 * avg_rtt < avg_irt ? avg_irt / 4 : 1.5 * avg_rtt)) { write_port(sp); } /* * When all ports being probed seem to be active, send a test probe * to see if the host is still alive. */ if (time_since(last_reply) > 3 * (avg_rtt == 0 ? 1 : avg_rtt < avg_irt ? avg_irt : avg_rtt) && find_port_info(test_portno) == 0) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -