/* * ipx_probe.c * * Check the network for frames currently active * * Copyright (C) 1996 by Volker Lendecke * */ #include #include #include #include #include #include #include #include #include #include #include static char *progname; int verbose = 0; static void usage() { fprintf(stderr, "usage: %s [options]\n", progname); fprintf(stderr, "type '%s -h' for help\n", progname); } static void help() { printf("\n" "Probe an interface for ipx networks\n" "\n"); printf("usage: %s [options]\n", progname); printf("\n" "-v Verbose output\n" "-i interface Interface to probe, default: eth0\n" "-t timeout Seconds to wait for answer, default: 3\n" "-h Print this help text\n\n"); } #define IPX_SAP_PTYPE (0x04) #define IPX_SAP_NEAREST_QUERY (0x0003) #define IPX_SAP_PORT (0x0452) #define IPX_BROADCAST_NODE ("\xff\xff\xff\xff\xff\xff") #define BVAL(buf,pos) (((__u8 *)(buf))[pos]) #define BSET(buf,pos,val) (BVAL(buf,pos) = (val)) static inline void WSET_HL(__u8 * buf, int pos, __u16 val) { BSET(buf, pos, val >> 8); BSET(buf, pos + 1, val & 0xff); } struct frame_type { char *ft_name; unsigned char ft_val; }; static struct frame_type frame_types[] = { { "802.2", IPX_FRAME_8022 } , #ifdef IPX_FRAME_TR_8022 { "802.2TR", IPX_FRAME_TR_8022 } , #endif { "802.3", IPX_FRAME_8023 } , { "SNAP", IPX_FRAME_SNAP } , { "EtherII", IPX_FRAME_ETHERII } }; #define NFTYPES (sizeof(frame_types)/sizeof(struct frame_type)) static char * frame_name(int frame_type) { int i; for (i = 0; i < NFTYPES; i++) { if (frame_types[i].ft_val == frame_type) { return frame_types[i].ft_name; } } return NULL; } static int ipx_recvfrom(int sock, void *buf, int len, unsigned int flags, struct sockaddr_ipx *sender, int *addrlen, int timeout, long *err) { fd_set rd, wr, ex; struct timeval tv; int result; FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&ex); FD_SET(sock, &rd); tv.tv_sec = timeout; tv.tv_usec = 0; if ((result = select(sock + 1, &rd, &wr, &ex, &tv)) == -1) { *err = errno; return -1; } if (FD_ISSET(sock, &rd)) { result = recvfrom(sock, buf, len, flags, (struct sockaddr *) sender, addrlen); } else { result = -1; errno = ETIMEDOUT; } if (result < 0) { *err = errno; } return result; } static int ipx_recv(int sock, void *buf, int len, unsigned int flags, int timeout, long *err) { struct sockaddr_ipx sender; int addrlen = sizeof(sender); return ipx_recvfrom(sock, buf, len, flags, &sender, &addrlen, timeout, err); } static int probe_frame(char *interface, int frame_type, int timeout, unsigned long *net) { int i, sock, opt; int result; long err; char errmsg[strlen(progname) + 20]; char data[1024]; static struct ifreq id; struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &id.ifr_addr; if (verbose != 0) { printf("probing %s on %s -- ", frame_name(frame_type), interface); fflush(stdout); } sock = socket(AF_IPX, SOCK_DGRAM, AF_IPX); if (sock < 0) { int old_errno = errno; sprintf(errmsg, "%s: socket", progname); perror(errmsg); if (old_errno == -EINVAL) { fprintf(stderr, "Probably you have no IPX support in " "your kernel\n"); } close(sock); return -1; } memset(&id, 0, sizeof(id)); strncpy(id.ifr_name, interface, sizeof(id.ifr_name)-1); sipx->sipx_family = AF_IPX; sipx->sipx_action = IPX_CRTITF; sipx->sipx_special = IPX_PRIMARY; sipx->sipx_network = 0L; sipx->sipx_type = frame_type; i = 0; do { result = ioctl(sock, SIOCSIFADDR, &id); i++; } while ((i < 5) && (result < 0) && (errno == EAGAIN)); if (result < 0) { int old_errno = errno; close(sock); errno = old_errno; return result; } /* We do a GNS request on the new socket. If something comes back, we assume that the frame type is valid. */ opt = 1; if ((result = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt))) < 0) { int old_errno = errno; close(sock); errno = old_errno; return result; } memset(&id, 0, sizeof(id)); sipx->sipx_family = AF_IPX; sipx->sipx_network = htonl(0x0); sipx->sipx_port = htons(0x0); sipx->sipx_type = IPX_SAP_PTYPE; if ((result = bind(sock, (struct sockaddr *)sipx, sizeof(*sipx))) < 0 -1) { int old_errno = errno; close(sock); errno = old_errno; return result; } WSET_HL(data, 0, IPX_SAP_NEAREST_QUERY); WSET_HL(data, 2, 4); memset(&id, 0, sizeof(id)); sipx->sipx_family = AF_IPX; sipx->sipx_port = htons(IPX_SAP_PORT); sipx->sipx_type = IPX_SAP_PTYPE; sipx->sipx_network = htonl(0x0); memcpy(sipx->sipx_node, IPX_BROADCAST_NODE, 6); if ((result = sendto(sock, data, 4, 0, (struct sockaddr *) sipx, sizeof(*sipx))) < 0) { int old_errno = errno; close(sock); errno = old_errno; return result; } result = ipx_recv(sock, data, 1024, 0, timeout, &err); if (result > 0) { struct sockaddr_ipx sipx; int namelen = sizeof(sipx); if (getsockname(sock, (struct sockaddr *)&sipx, &namelen) < 0) { fprintf(stderr, "%s: Could not find socket address\n", progname); exit(1); } *net = ntohl(sipx.sipx_network); } memset(&id, 0, sizeof(id)); strncpy(id.ifr_name, interface, sizeof(id.ifr_name)-1); sipx->sipx_family = AF_IPX; sipx->sipx_action = IPX_DLTITF; sipx->sipx_network = 0L; sipx->sipx_type = frame_type; result = ioctl(sock, SIOCSIFADDR, &id); close(sock); if (result < 0) { fprintf(stderr, "%s: could not delete interface\n", progname); exit(1); } if (err == ETIMEDOUT) { if (verbose != 0) { printf("no network found\n"); } return -1; } if (verbose != 0) { printf("found IPX network %8.8lX\n", *net); } return 0; } static int file_lines(char *name) { FILE *f = fopen(name, "r"); char buf[100]; int lines = 0; if (f == NULL) { return -errno; } while (fgets(buf, sizeof(buf), f) != NULL) { lines += 1; } fclose(f); return lines; } static int ipx_interfaces(void) { int result = file_lines("/proc/net/ipx_interface"); if (result == 0) { result = -EIO; } return result - 1; } static int ipx_auto_off(void) { int s; char errmsg[strlen(progname) + 20]; int val = 0; s = socket(AF_IPX, SOCK_DGRAM, AF_IPX); if (s < 0) { int old_errno = errno; sprintf(errmsg, "%s: socket", progname); perror(errmsg); if (old_errno == -EINVAL) { fprintf(stderr, "Probably you have no IPX support in " "your kernel\n"); } close(s); return -1; } sprintf(errmsg, "%s: ioctl", progname); if (ioctl(s, SIOCAIPXPRISLT, &val) < 0) { perror(errmsg); close(s); return -1; } if (ioctl(s, SIOCAIPXITFCRT, &val) < 0) { perror(errmsg); close(s); return -1; } close(s); return 0; } int main(int argc, char *argv[]) { int interfaces; char *interface = "eth0"; int opt; int timeout = 3; unsigned long network[5] = { 0, }; progname = argv[0]; while ((opt = getopt(argc, argv, "vi:ht:")) != EOF) { switch(opt) { case 'v': verbose = 1; break; case 'i': interface = optarg; break; case 't': timeout = atoi(optarg); break; case 'h': help(); exit(1); default: usage(); exit(1); } } if (ipx_auto_off() < 0) { exit(1); } interfaces = ipx_interfaces(); if (interfaces > 0) { fprintf(stderr, "%s must be run with no interfaces configured." " Found %d interface%s.\n", progname, interfaces, interfaces == 1 ? "" : "s"); exit(1); } if (interfaces < 0) { fprintf(stderr, "%s: %s\n", progname, strerror(interfaces)); exit(1); } probe_frame(interface, IPX_FRAME_8022, timeout, &(network[0])); probe_frame(interface, IPX_FRAME_8023, timeout, &(network[1])); probe_frame(interface, IPX_FRAME_SNAP, timeout, &(network[2])); probe_frame(interface, IPX_FRAME_ETHERII, timeout, &(network[3])); if (verbose == 0) { if (network[0] != 0) { printf("%s %8.8lX\n", frame_name(IPX_FRAME_8022), network[0]); } if (network[1] != 0) { printf("%s %8.8lX\n", frame_name(IPX_FRAME_8023), network[1]); } if (network[2] != 0) { printf("%s %8.8lX\n", frame_name(IPX_FRAME_SNAP), network[2]); } if (network[3] != 0) { printf("%s %8.8lX\n", frame_name(IPX_FRAME_ETHERII), network[3]); } } return 0; }