pax_global_header00006660000000000000000000000064121040136630014506gustar00rootroot0000000000000052 comment=258dbb1c7f8672c09a4a578fc17dada524c3eabb lltdscan-master/000077500000000000000000000000001210401366300141475ustar00rootroot00000000000000lltdscan-master/.gitignore000066400000000000000000000000111210401366300161270ustar00rootroot00000000000000lltdscan lltdscan-master/Makefile000066400000000000000000000026651210401366300156200ustar00rootroot00000000000000TARGETS=lltdscan CD=cd CP=cp TAR=tar GPG=gpg MAKE=make RM=rm SUDO=sudo CC=gcc # explicit pcap include dir is for redhat which is fux0red CFLAGS=-g -I/usr/local/include -L/usr/local/lib -DFINDIF=$(FINDIF) -DUSE_NETIF=$(USE_NETIF) -DOPENBSD=$(OPENBSD) -DLINUX=$(LINUX) -DSOLARIS=$(SOLARIS) -DFREEBSD=$(FREEBSD) -DMACOSX=$(MACOSX) -I/usr/include/pcap -L/opt/csw/lib -R/opt/csw/lib CFLAGS2=-g -I/usr/local/include -I/usr/local/include/libnet-1.1 -I/usr/include/pcap -I/usr/local/include/libnet11 LDFLAGS2=-g -L/usr/local/lib -L/usr/local/lib/libnet-1.1 -L/opt/csw/lib -L/usr/local/lib/libnet11 -L/usr/local/lib/libnet113 all: lltdscan doc: arping.yodl yodl2man -o arping.8 arping.yodl install: install -c lltdscan /usr/local/bin/lltdscan install lltdscan.8 /usr/local/man/man8/lltdscan.8 SYS=$(shell uname -s) ifeq ($(SYS),SunOS) EXTRA_LIBS=-lsocket -lnsl endif lltdscan: lltdscan.c lltd.c $(CC) $(CFLAGS2) $(LDFLAGS2) -o lltdscan lltdscan.c -lnet -lpcap -lrt $(EXTRA_LIBS) clean: rm -f *.o $(TARGETS) distclean: clean rm -f config{.cache,.h,.log,.status} V=$(shell grep version arping-2/arping.c|grep const|sed 's:[a-z =]*::;s:f;::') DFILE=arping-$(V).tar.gz DDIR=arping-$(V) dist: ($(CD) ..; \ $(CP) -ax arping $(DDIR); \ $(RM) -fr $(DDIR)/{.\#*,CVS,.svn,*~} \ $(DDIR)/arping-2/{.\#*,CVS,.svn,*~}; \ $(MAKE) -C $(DDIR) doc; \ $(TAR) cfz $(DFILE) $(DDIR); \ $(GPG) -b -a $(DFILE); \ ) maintainerclean: distclean rm -f config{.h.in,ure} lltdscan-master/README000066400000000000000000000032021210401366300150240ustar00rootroot00000000000000= DESCRIPTION = lltdscan - Scan for LLTD-enabled hosts on your network. LLTD is a Link Layer Topology Discovery Protocol. protocol specs are available from Microsoft at http://www.microsoft.com/whdc/connect/Rally/LLTD-spec.mspx Run "lltdscan -i em0" on your FreeBSD or Linux-based pc - and you'll see all your neighbours that have the MS Windows installed and have not unchecked the "Link-Layer Topology Discovery Responder" in their Network Connection settings. Works starting from XP(sp3 ?), works on Vista, needs testing on W2k7. IMPORTANT: LLTD is a level 2 protocol - i.e. it not runs over ip or tcp or udp or anything. So, you can get other PC's info even if they live in different IP subnets, or even if they don't have any valid IP address but have 169.254.x.y self-assigned IP. = INSTALLATION = FreeBSD: gmake && gmake install Linux: make && cp lltdscan /usr/sbin/ && cp lltdscan.8 /usr/share/man/man8/ = EXAMPLES = #sudo ./lltdscan -t1300 interface eth0 101 bytes from 00:01:33:ed:54:a1 (192.168.123.12 ): time=929 ms name="XZ" found 1 hosts in 1.303 seconds #sudo ./lltdscan -t1300 -v interface eth0 101 bytes from 00:01:33:ed:54:a1 (192.168.123.12 ): time=929 ms name="XZ" Host ID: 00 01 ee ff 22 a1 Charact.: 20 00 00 00 (full-duplex) Media: 00 00 00 06 (Ethernet) Perf.cntr: 00 00 00 00 00 36 9e 99 Link speed: 100 Mbit/s Name: 31 00 43 00 QoS: 60 00 00 00 (802.1q-support, 802.1p-support) found 1 hosts in 1.302 seconds = LICENSE = Public Domain. = CONTACTS = zed [dot] 0xff [at] gmail.com http://github.com/zed-0xff/lltdscan http://zed.0xff.me/ lltdscan-master/lltd.c000066400000000000000000000066021210401366300152560ustar00rootroot00000000000000void hexdump(const u_char*p, int len){ int i; for(i=0; i= 10000){ sprintf(buf, "%d Mbit/s", spd/10000); } else { sprintf(buf, "%d kbit/s", spd/10); } break; case 0x0F: desc="Name"; break; case 0x14: desc="QoS"; if(p[2]&0x80) strcat(comment, "qWave-enabled, "); if(p[2]&0x40) strcat(comment, "802.1q-support, "); if(p[2]&0x20) strcat(comment, "802.1p-support, "); if(*comment){ comment[strlen(comment)-2] = 0; } break; } if(!desc) sprintf(desc=buf, "0x%02x", *p); printf(" %10s: ", desc); if( *buf && desc!=buf) printf("%s",buf); else hexdump(p+2,len); if( *comment ){ printf("\t(%s)", comment); } puts(""); } u_char* lltd_extract_name(const u_char*p){ u_char l; static u_char namebuf[0x40]; while(*p){ l = p[1]; if( *p == 0x0F ){ int namelen = l/2; if( namelen >= sizeof(namebuf) ){ namelen = sizeof(namebuf) - 1; } p += 2; // name is in UTF8 char *pbuf; for(pbuf=namebuf; namelen>0; p++, namelen--){ *pbuf++ = *p++; } *pbuf = 0; return namebuf; } p += l + 2; } return NULL; } u_char* lltd_extract_unicode_name(const u_char*p){ u_char l; static u_char namebuf[0x40]; while(*p){ l = p[1]; if( *p == 0x0F ){ int namelen = l/2; p += 2; u_char *pbuf; /* convert ucs-2le to utf-8 */ /* FIXME: maybe, this is utf-16le, not ucs-2le? */ for(pbuf=namebuf; namelen>0; namelen--){ unsigned short ch = *p++; ch |= ((unsigned short)*p++) << 8; if(ch >= 0xd800 && ch <= 0xdfff){ static int once; if(!once++) fprintf(stderr, "Warning: utf-16 unsupported, please report\n"); } if(ch >= 0x800){ if(pbuf - namebuf + 3 >= sizeof(namebuf)) break; *pbuf++ = 0xe0 | ((ch >> 12) & 0x0f); *pbuf++ = 0x80 | ((ch >> 6) & 0x3f); *pbuf++ = 0x80 | ( ch & 0x3f); continue; } if(ch >= 0x80){ if(pbuf - namebuf + 2 >= sizeof(namebuf)) break; *pbuf++ = 0xc0 | ((ch >> 6) & 0x1f); *pbuf++ = 0x80 | ( ch & 0x3f); continue; } if (pbuf - namebuf + 1 >= sizeof(namebuf)) break; *pbuf++ = ch; } *pbuf = 0; return namebuf; } p += l + 2; } return NULL; } u_char* lltd_extract_ip(const u_char*p){ u_char l; static u_char buf[20]; while(*p){ l = p[1]; if( *p == 0x07 ){ sprintf(buf, "%d.%d.%d.%d", p[2], p[3], p[4], p[5]); return buf; } p += l + 2; } return NULL; } void lltd_dump(const u_char*p){ u_char l; while(*p){ l = p[1]; lltd_dump_tlv(p,l); p += l + 2; } } lltdscan-master/lltdscan.8000066400000000000000000000023311210401366300160430ustar00rootroot00000000000000.TH "lltdscan" "8" "4th September, 2009" "lltdscan" "" .PP .SH "NAME" lltdscan \- scan for LLTD-enabled hosts on a network interface\&. .PP .SH "SYNOPSIS" \fBlltdscan\fP [-i \fIiface\fP] [-t \fItimeout\fP] [-u] [-v] [-v] [aa:bb:cc:dd:ee:ff] .PP .SH "DESCRIPTION" The \fIlltdscan\fP utility sends broadcast \fBLLTD\fP request on specified (or default) interface. And then listens for \fBtimeout\fP milliseconds for responses\&. .PP Add one or two \fB-v\fP options to increase verbosity\&. .PP Add \fB-u\fP option to show machine names in UTF-8\&. .PP Also you can specify exactly one \fBMAC\fP address as last argument - and \fBlltdscan\fP will exit as soon as it receives first reply from specified host\&. .SH "LLTD PROTOCOL" \fBLLTD\fP stands for "Link Layer Topology Discovery"\&. .PP Protocol specs are available from Microsoft at http://www\&.microsoft\&.com/whdc/connect/Rally/LLTD-spec\&.mspx .SH "SEE ALSO" .PP \fBping(8)\fP, \fBarp(8)\fP, \fBarping(8)\fP .SH "AVAILABILITY" Check for latest versions at http://github\&.com/zed-0xff/lltdscan .PP And feel free to visit my personal technical blog at http://zed\&.0xff\&.me/ for more fun & useful tools and patches :) .SH "AUTHOR" Andrey Zaikin \&. lltdscan-master/lltdscan.c000066400000000000000000000171031210401366300161210ustar00rootroot00000000000000#include #include #include #include #include #include #include "lltd.c" #define PCAP_PERIOD 100 // pcap kernel poll period, ms void usage(char *name) { fprintf(stderr, "usage: %s [-i iface] [-t timeout] [-u] [-v] [-v] [aa:bb:cc:dd:ee:ff]\n\n" "\t timeout is in milliseconds;\n" "\t add -u to show machine names in UTF-8;\n" "\t add -v or -vv increase verbosity;\n" "\t last argument is an optional single MAC-address of interest.\n", name); } static int do_stop=0; static timer_t timer_id; static struct timeval start_time; static int verbose = 0; static int unicode = 0; static uint64_t hosts[200]; static int nhosts = 0; static u_char* mac_to_find = NULL; static int mac_found = 0; static pcap_t *pcap_handle; // converts timeval diff to milliseconds long tv_diff2msec(const struct timeval*ptv){ struct timeval curtime; if(!ptv){ gettimeofday(&curtime, NULL); ptv = &curtime; } time_t dsec = ptv->tv_sec - start_time.tv_sec; long dmsec = (ptv->tv_usec - start_time.tv_usec)/1000; while( dsec > 0 ){ dsec--; dmsec += 1000; } return dmsec; } void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet){ time_t dsec; suseconds_t dmsec; u_char *p; int i,j; uint64_t host_id=0; char mac[0x20]; if( header->caplen < 100) return; // skip some unknown very small pkts memcpy(&host_id, packet+48, 6); for(i=0; icaplen, mac, lltd_extract_ip(packet+46), tv_diff2msec(&header->ts), unicode ? lltd_extract_unicode_name(packet+46) : lltd_extract_name(packet+46) ); if(verbose == 1){ puts(""); lltd_dump(packet+46); } else if(verbose == 2){ printf("\n\t"); for(i=46,j=0; icaplen; i++){ printf("%02x ",packet[i]); j++; if(j == 16){ printf("\n\t"); j=0; } } } puts(""); } void on_alarm(int v){ do_stop = 1; } #if PCAP_ERRBUF_SIZE > LIBNET_ERRBUF_SIZE #define ERRBUF_SIZE PCAP_ERRBUF_SIZE #else #define ERRBUF_SIZE LIBNET_ERRBUF_SIZE #endif int main (int argc, char *argv[]){ char *dev = NULL; char errbuf [ERRBUF_SIZE]; /* Error string */ struct bpf_program fp; /* The compiled filter */ char filter_exp[] = "ether proto 0x88d9"; //"port 80"; /* The filter expression */ bpf_u_int32 mask; /* Our netmask */ bpf_u_int32 net; /* Our IP */ struct pcap_pkthdr header; const u_char *packet; int c,i; libnet_t *l; libnet_ptag_t eth_ptag = 0; u_char buf[0x100]; struct itimerspec tspec; memset(&tspec, 0, sizeof(tspec)); tspec.it_value.tv_sec = 3; while ((c = getopt(argc, argv, "t:i:hvu")) != EOF) { switch (c) { case 'i': // interface dev = optarg; break; case 't': // timeout i = atoi(optarg); if( i>0 ){ #ifndef __linux__ if( i > PCAP_PERIOD ) i-=PCAP_PERIOD-10; // try to be more precise #endif tspec.it_value.tv_sec = i/1000; tspec.it_value.tv_nsec = (i%1000)*1000000; } break; case 'v': // verbosity verbose++; break; case 'u': // unicode support unicode = 1; break; case 'h': // show usage usage(argv[0]); exit(EXIT_SUCCESS); default: exit(EXIT_FAILURE); } } argc -= optind; argv += optind; if( argc > 1 ){ usage(argv[0]); exit(EXIT_FAILURE); } if( argc == 1 ){ if( strlen(argv[0]) != 17 ){ fprintf(stderr, "Invalid MAC-address: '%s'\n", argv[0]); exit(EXIT_FAILURE); } mac_to_find = argv[0]; } setlinebuf(stdout); if(!dev) dev = pcap_lookupdev(errbuf); if (dev == NULL) { fprintf(stderr, "Couldn't find default device: %s\n", errbuf); return (2); } printf("interface %s\n",dev); l = libnet_init(LIBNET_LINK, dev, errbuf); if (l == NULL) { fprintf(stderr, "libnet_init() failed: %s", errbuf); exit(EXIT_FAILURE); } /* Find the properties for the device */ if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) { fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf); net = 0; mask = 0; } struct ether_addr *ha = NULL; if ((ha = (struct ether_addr *) libnet_get_hwaddr(l)) == NULL) { fprintf(stderr, "%s", libnet_geterror(l)); exit(EXIT_FAILURE); } // LLTP magic packet char* payload = "\x01\x00\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00"; char* hwdst = "\xff\xff\xff\xff\xff\xff"; memcpy(buf,payload,18); memcpy(buf+10, ha, 6); gettimeofday(&start_time, NULL); memcpy(buf+16, &start_time.tv_sec, 2); // emulate sequence number eth_ptag = libnet_build_ethernet( hwdst, /* ethernet destination */ ha->ether_addr_octet, /* ethernet source */ 0x88d9, /* protocol type */ buf, /* payload */ 18, /* payload size */ l, /* libnet handle */ 0); /* libnet id */ if (eth_ptag == -1) { fprintf(stderr, "Can't build ethernet header: %s\n", libnet_geterror(l)); libnet_destroy(l); exit(EXIT_FAILURE); } /* * Write it to the wire. */ c = libnet_write(l); if (c == -1) { fprintf(stderr, "Write error: %s\n", libnet_geterror(l)); libnet_destroy(l); exit(EXIT_FAILURE); } /* Open the session in promiscuous mode */ pcap_handle = pcap_open_live(dev, BUFSIZ, 1, PCAP_PERIOD, errbuf); if (pcap_handle == NULL) { fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf); libnet_destroy(l); return (2); } /* Compile and apply the filter */ if (pcap_compile(pcap_handle, &fp, filter_exp, 0, net) == -1) { fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(pcap_handle)); libnet_destroy(l); return (2); } if (pcap_setfilter(pcap_handle, &fp) == -1) { fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(pcap_handle)); libnet_destroy(l); return (2); } signal(SIGALRM, on_alarm); gettimeofday(&start_time, NULL); timer_create(CLOCK_MONOTONIC, NULL, &timer_id); timer_settime(timer_id, 0, &tspec, NULL); // don't know why, but pcap_dispatch does not return control to main after // timeout expires. so, we use nonblocking pcap on linux. #ifdef __linux__ pcap_setnonblock(pcap_handle, 1, errbuf); #endif while( !do_stop ){ pcap_dispatch(pcap_handle, -1, got_packet, NULL); #ifdef __linux__ usleep(1000); #endif } pcap_close(pcap_handle); i = tv_diff2msec(NULL); printf("found %d hosts in %d.%d seconds", nhosts, i/1000, i%1000); if( mac_to_find && !mac_found ){ printf(", but '%s' is not found.\n", mac_to_find); } else { puts(""); } return (0); }