Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

1020 lines (891 sloc) 35.431 kb
/*
* pcap-sita.c: Packet capture interface additions for SITA ACN devices
*
* Copyright (c) 2007 Fulko Hew, SITA INC Canada, Inc <fulko.hew@sita.aero>
*
* License: BSD
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. The names of the authors may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "pcap-int.h"
#include "pcap-sita.h"
/* non-configureable manifests follow */
#define IOP_SNIFFER_PORT 49152 /* TCP port on the IOP used for 'distributed pcap' usage */
#define MAX_LINE_SIZE 255 /* max size of a buffer/line in /etc/hosts we allow */
#define MAX_CHASSIS 8 /* number of chassis in an ACN site */
#define MAX_GEOSLOT 8 /* max number of access units in an ACN site */
#define FIND 0
#define LIVE 1
typedef struct iface {
struct iface *next; /* a pointer to the next interface */
char *name; /* this interface's name */
char *IOPname; /* this interface's name on an IOP */
uint32_t iftype; /* the type of interface (DLT values) */
} iface_t;
typedef struct unit {
char *ip; /* this unit's IP address (as extracted from /etc/hosts) */
int fd; /* the connection to this unit (if it exists) */
int find_fd; /* a big kludge to avoid my programming limitations since I could have this unit open for findalldevs purposes */
int first_time; /* 0 = just opened via acn_open_live(), ie. the first time, NZ = nth time */
struct sockaddr_in *serv_addr; /* the address control block for comms to this unit */
int chassis;
int geoslot;
iface_t *iface; /* a pointer to a linked list of interface structures */
char *imsg; /* a pointer to an inbound message */
int len; /* the current size of the inbound message */
} unit_t;
static unit_t units[MAX_CHASSIS+1][MAX_GEOSLOT+1]; /* we use indexes of 1 through 8, but we reserve/waste index 0 */
static fd_set readfds; /* a place to store the file descriptors for the connections to the IOPs */
static int max_fs;
pcap_if_t *acn_if_list; /* pcap's list of available interfaces */
static void dump_interface_list(void) {
pcap_if_t *iff;
pcap_addr_t *addr;
int longest_name_len = 0;
char *n, *d, *f;
int if_number = 0;
iff = acn_if_list;
while (iff) {
if (iff->name && (strlen(iff->name) > longest_name_len)) longest_name_len = strlen(iff->name);
iff = iff->next;
}
iff = acn_if_list;
printf("Interface List:\n");
while (iff) {
n = (iff->name) ? iff->name : "";
d = (iff->description) ? iff->description : "";
f = (iff->flags == PCAP_IF_LOOPBACK) ? "L" : "";
printf("%3d: %*s %s '%s'\n", if_number++, longest_name_len, n, f, d);
addr = iff->addresses;
while (addr) {
printf("%*s ", (5 + longest_name_len), ""); /* add some indentation */
printf("%15s ", (addr->addr) ? inet_ntoa(((struct sockaddr_in *)addr->addr)->sin_addr) : "");
printf("%15s ", (addr->netmask) ? inet_ntoa(((struct sockaddr_in *)addr->netmask)->sin_addr) : "");
printf("%15s ", (addr->broadaddr) ? inet_ntoa(((struct sockaddr_in *)addr->broadaddr)->sin_addr) : "");
printf("%15s ", (addr->dstaddr) ? inet_ntoa(((struct sockaddr_in *)addr->dstaddr)->sin_addr) : "");
printf("\n");
addr = addr->next;
}
iff = iff->next;
}
}
static void dump(unsigned char *ptr, int i, int indent) {
fprintf(stderr, "%*s", indent, " ");
for (; i > 0; i--) {
fprintf(stderr, "%2.2x ", *ptr++);
}
fprintf(stderr, "\n");
}
static void dump_interface_list_p(void) {
pcap_if_t *iff;
pcap_addr_t *addr;
int if_number = 0;
iff = acn_if_list;
printf("Interface Pointer @ %p is %p:\n", &acn_if_list, iff);
while (iff) {
printf("%3d: %p %p next: %p\n", if_number++, iff->name, iff->description, iff->next);
dump((unsigned char *)iff, sizeof(pcap_if_t), 5);
addr = iff->addresses;
while (addr) {
printf(" %p %p %p %p, next: %p\n", addr->addr, addr->netmask, addr->broadaddr, addr->dstaddr, addr->next);
dump((unsigned char *)addr, sizeof(pcap_addr_t), 10);
addr = addr->next;
}
iff = iff->next;
}
}
static void dump_unit_table(void) {
int chassis, geoslot;
iface_t *p;
printf("%c:%c %s %s\n", 'C', 'S', "fd", "IP Address");
for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {
for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
if (units[chassis][geoslot].ip != NULL)
printf("%d:%d %2d %s\n", chassis, geoslot, units[chassis][geoslot].fd, units[chassis][geoslot].ip);
p = units[chassis][geoslot].iface;
while (p) {
char *n = (p->name) ? p->name : "";
char *i = (p->IOPname) ? p->IOPname : "";
p = p->next;
printf(" %12s -> %12s\n", i, n);
}
}
}
}
static int find_unit_by_fd(int fd, int *chassis, int *geoslot, unit_t **unit_ptr) {
int c, s;
for (c = 0; c <= MAX_CHASSIS; c++) {
for (s = 0; s <= MAX_GEOSLOT; s++) {
if (units[c][s].fd == fd || units[c][s].find_fd == fd) {
if (chassis) *chassis = c;
if (geoslot) *geoslot = s;
if (unit_ptr) *unit_ptr = &units[c][s];
return 1;
}
}
}
return 0;
}
static int read_client_nbytes(int fd, int count, unsigned char *buf) {
unit_t *u;
int chassis, geoslot;
int len;
find_unit_by_fd(fd, &chassis, &geoslot, &u);
while (count) {
if ((len = recv(fd, buf, count, 0)) <= 0) return -1; /* read in whatever data was sent to us */
count -= len;
buf += len;
} /* till we have everything we are looking for */
return 0;
}
static void empty_unit_iface(unit_t *u) {
iface_t *p, *cur;
cur = u->iface;
while (cur) { /* loop over all the interface entries */
if (cur->name) free(cur->name); /* throwing away the contents if they exist */
if (cur->IOPname) free(cur->IOPname);
p = cur->next;
free(cur); /* then throw away the structure itself */
cur = p;
}
u->iface = 0; /* and finally remember that there are no remaining structure */
}
static void empty_unit(int chassis, int geoslot) {
unit_t *u = &units[chassis][geoslot];
empty_unit_iface(u);
if (u->imsg) { /* then if an inbound message buffer exists */
u->imsg = (char *)realloc(u->imsg, 1); /* and re-allocate the old large buffer into a new small one */
if (u->imsg == NULL) { /* oops, realloc call failed */
fprintf(stderr, "Warning...call to realloc() failed, value of errno is %d\n", errno);
}
}
static void empty_unit_table(void) {
int chassis, geoslot;
for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {
for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
if (units[chassis][geoslot].ip != NULL) {
free(units[chassis][geoslot].ip); /* get rid of the malloc'ed space that holds the IP address */
units[chassis][geoslot].ip = 0; /* then set the pointer to NULL */
}
empty_unit(chassis, geoslot);
}
}
}
static char *find_nth_interface_name(int n) {
int chassis, geoslot;
iface_t *p;
char *last_name = 0;
if (n < 0) n = 0; /* ensure we are working with a valid number */
for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { /* scan the table... */
for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
if (units[chassis][geoslot].ip != NULL) {
p = units[chassis][geoslot].iface;
while (p) { /* and all interfaces... */
if (p->IOPname) last_name = p->name; /* remembering the last name found */
if (n-- == 0) return last_name; /* and if we hit the instance requested */
p = p->next;
}
}
}
}
/* if we couldn't fine the selected entry */
if (last_name) return last_name; /* ... but we did have at least one entry... return the last entry found */
return ""; /* ... but if there wasn't any entry... return an empty string instead */
}
int acn_parse_hosts_file(char *errbuf) { /* returns: -1 = error, 0 = OK */
FILE *fp;
char buf[MAX_LINE_SIZE];
char *ptr, *ptr2;
int pos;
int chassis, geoslot;
unit_t *u;
empty_unit_table();
if ((fp = fopen("/etc/hosts", "r")) == NULL) { /* try to open the hosts file and if it fails */
snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot open '/etc/hosts' for reading."); /* return the nohostsfile error response */
return -1;
}
while (fgets(buf, MAX_LINE_SIZE-1, fp)) { /* while looping over the file */
pos = strcspn(buf, "#\n\r"); /* find the first comment character or EOL */
*(buf + pos) = '\0'; /* and clobber it and anything that follows it */
pos = strspn(buf, " \t"); /* then find the first non-white space */
if (pos == strlen(buf)) /* if there is nothing but white space on the line */
continue; /* ignore that empty line */
ptr = buf + pos; /* and skip over any of that leading whitespace */
if ((ptr2 = strstr(ptr, "_I_")) == NULL) /* skip any lines that don't have names that look like they belong to IOPs */
continue;
if (*(ptr2 + 4) != '_') /* and skip other lines that have names that don't look like ACN components */
continue;
*(ptr + strcspn(ptr, " \t")) = '\0'; /* null terminate the IP address so its a standalone string */
chassis = *(ptr2 + 3) - '0'; /* extract the chassis number */
geoslot = *(ptr2 + 5) - '0'; /* and geo-slot number */
if (chassis < 1 || chassis > MAX_CHASSIS ||
geoslot < 1 || geoslot > MAX_GEOSLOT) { /* if the chassis and/or slot numbers appear to be bad... */
snprintf(errbuf, PCAP_ERRBUF_SIZE, "Invalid ACN name in '/etc/hosts'."); /* warn the user */
continue; /* and ignore the entry */
}
if ((ptr2 = (char *)malloc(strlen(ptr) + 1)) == NULL) {
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
continue;
}
strcpy(ptr2, ptr); /* copy the IP address into our malloc'ed memory */
u = &units[chassis][geoslot];
u->ip = ptr2; /* and remember the whole shebang */
u->chassis = chassis;
u->geoslot = geoslot;
}
fclose(fp);
if (*errbuf) return -1;
else return 0;
}
static int open_with_IOP(unit_t *u, int flag) {
int sockfd;
char *ip;
if (u->serv_addr == NULL) {
u->serv_addr = malloc(sizeof(struct sockaddr_in));
/* since we called malloc(), lets check to see if we actually got the memory */
if (u->serv_addr == NULL) { /* oops, we didn't get the memory requested */
fprintf(stderr, "malloc() request for u->serv_addr failed, value of errno is: %d\n", errno);
return 0;
}
}
ip = u->ip;
/* bzero() is deprecated, replaced with memset() */
memset((char *)u->serv_addr, 0, sizeof(struct sockaddr_in));
u->serv_addr->sin_family = AF_INET;
u->serv_addr->sin_addr.s_addr = inet_addr(ip);
u->serv_addr->sin_port = htons(IOP_SNIFFER_PORT);
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "pcap can't open a socket for connecting to IOP at %s\n", ip);
return 0;
}
if (connect(sockfd, (struct sockaddr *)u->serv_addr, sizeof(struct sockaddr_in)) < 0) {
fprintf(stderr, "pcap can't connect to IOP at %s\n", ip);
return 0;
}
if (flag == LIVE) u->fd = sockfd;
else u->find_fd = sockfd;
u->first_time = 0;
return sockfd; /* return the non-zero file descriptor as a 'success' indicator */
}
static void close_with_IOP(int chassis, int geoslot, int flag) {
int *id;
if (flag == LIVE) id = &units[chassis][geoslot].fd;
else id = &units[chassis][geoslot].find_fd;
if (*id) { /* this was the last time, so... if we are connected... */
close(*id); /* disconnect us */
*id = 0; /* and forget that the descriptor exists because we are not open */
}
}
static void pcap_cleanup_acn(pcap_t *handle) {
int chassis, geoslot;
unit_t *u;
if (find_unit_by_fd(handle->fd, &chassis, &geoslot, &u) == 0)
return;
close_with_IOP(chassis, geoslot, LIVE);
if (u)
u->first_time = 0;
pcap_cleanup_live_common(handle);
}
static void send_to_fd(int fd, int len, unsigned char *str) {
int nwritten;
int chassis, geoslot;
while (len > 0) {
if ((nwritten = write(fd, str, len)) <= 0) {
find_unit_by_fd(fd, &chassis, &geoslot, NULL);
if (units[chassis][geoslot].fd == fd) close_with_IOP(chassis, geoslot, LIVE);
else if (units[chassis][geoslot].find_fd == fd) close_with_IOP(chassis, geoslot, FIND);
empty_unit(chassis, geoslot);
return;
}
len -= nwritten;
str += nwritten;
}
}
static void acn_freealldevs(void) {
pcap_if_t *iff, *next_iff;
pcap_addr_t *addr, *next_addr;
for (iff = acn_if_list; iff != NULL; iff = next_iff) {
next_iff = iff->next;
for (addr = iff->addresses; addr != NULL; addr = next_addr) {
next_addr = addr->next;
if (addr->addr) free(addr->addr);
if (addr->netmask) free(addr->netmask);
if (addr->broadaddr) free(addr->broadaddr);
if (addr->dstaddr) free(addr->dstaddr);
free(addr);
}
if (iff->name) free(iff->name);
if (iff->description) free(iff->description);
free(iff);
}
}
static void nonUnified_IOP_port_name(char *buf, size_t bufsize, const char *proto, unit_t *u) {
snprintf(buf, bufsize, "%s_%d_%d", proto, u->chassis, u->geoslot);
}
static void unified_IOP_port_name(char *buf, size_t bufsize, const char *proto, unit_t *u, int IOPportnum) {
int portnum;
portnum = ((u->chassis - 1) * 64) + ((u->geoslot - 1) * 8) + IOPportnum + 1;
snprintf(buf, bufsize, "%s_%d", proto, portnum);
}
static char *translate_IOP_to_pcap_name(unit_t *u, char *IOPname, bpf_u_int32 iftype) {
iface_t *iface_ptr, *iface;
char *name;
char buf[32];
char *proto;
char *port;
int IOPportnum = 0;
iface = malloc(sizeof(iface_t)); /* get memory for a structure */
if (iface == NULL) { /* oops, we didn't get the memory requested */
fprintf(stderr, "Error...couldn't allocate memory for interface structure...value of errno is: %d\n", errno);
return NULL;
}
memset((char *)iface, 0, sizeof(iface_t)); /* bzero is deprecated(), replaced with memset() */
iface->iftype = iftype; /* remember the interface type of this interface */
name = malloc(strlen(IOPname) + 1); /* get memory for the IOP's name */
if (name == NULL) { /* oops, we didn't get the memory requested */
fprintf(stderr, "Error...couldn't allocate memory for IOPname...value of errno is: %d\n", errno);
return NULL;
}
strcpy(name, IOPname); /* and copy it in */
iface->IOPname = name; /* and stick it into the structure */
if (strncmp(IOPname, "lo", 2) == 0) {
IOPportnum = atoi(&IOPname[2]);
switch (iftype) {
case DLT_EN10MB:
nonUnified_IOP_port_name(buf, sizeof buf, "lo", u);
break;
default:
unified_IOP_port_name(buf, sizeof buf, "???", u, IOPportnum);
break;
}
} else if (strncmp(IOPname, "eth", 3) == 0) {
IOPportnum = atoi(&IOPname[3]);
switch (iftype) {
case DLT_EN10MB:
nonUnified_IOP_port_name(buf, sizeof buf, "eth", u);
break;
default:
unified_IOP_port_name(buf, sizeof buf, "???", u, IOPportnum);
break;
}
} else if (strncmp(IOPname, "wan", 3) == 0) {
IOPportnum = atoi(&IOPname[3]);
switch (iftype) {
case DLT_SITA:
unified_IOP_port_name(buf, sizeof buf, "wan", u, IOPportnum);
break;
default:
unified_IOP_port_name(buf, sizeof buf, "???", u, IOPportnum);
break;
}
} else {
fprintf(stderr, "Error... invalid IOP name %s\n", IOPname);
return NULL;
}
name = malloc(strlen(buf) + 1); /* get memory for that name */
if (name == NULL) { /* oops, we didn't get the memory requested */
fprintf(stderr, "Error...couldn't allocate memory for IOP port name...value of errno is: %d\n", errno);
return NULL;
}
strcpy(name, buf); /* and copy it in */
iface->name = name; /* and stick it into the structure */
if (u->iface == 0) { /* if this is the first name */
u->iface = iface; /* stick this entry at the head of the list */
} else {
iface_ptr = u->iface;
while (iface_ptr->next) { /* othewise scan the list */
iface_ptr = iface_ptr->next; /* till we're at the last entry */
}
iface_ptr->next = iface; /* then tack this entry on the end of the list */
}
return iface->name;
}
static int if_sort(char *s1, char *s2) {
char *s1_p2, *s2_p2;
char str1[MAX_LINE_SIZE], str2[MAX_LINE_SIZE];
int s1_p1_len, s2_p1_len;
int retval;
if ((s1_p2 = strchr(s1, '_'))) { /* if an underscore is found... */
s1_p1_len = s1_p2 - s1; /* the prefix length is the difference in pointers */
s1_p2++; /* the suffix actually starts _after_ the underscore */
} else { /* otherwise... */
s1_p1_len = strlen(s1); /* the prefix length is the length of the string itself */
s1_p2 = 0; /* and there is no suffix */
}
if ((s2_p2 = strchr(s2, '_'))) { /* now do the same for the second string */
s2_p1_len = s2_p2 - s2;
s2_p2++;
} else {
s2_p1_len = strlen(s2);
s2_p2 = 0;
}
strncpy(str1, s1, (s1_p1_len > sizeof(str1)) ? s1_p1_len : sizeof(str1)); *(str1 + s1_p1_len) = 0;
strncpy(str2, s2, (s2_p1_len > sizeof(str2)) ? s2_p1_len : sizeof(str2)); *(str2 + s2_p1_len) = 0;
retval = strcmp(str1, str2);
if (retval != 0) return retval; /* if they are not identical, then we can quit now and return the indication */
return strcmp(s1_p2, s2_p2); /* otherwise we return the result of comparing the 2nd half of the string */
}
static void sort_if_table(void) {
pcap_if_t *p1, *p2, *prev, *temp;
int has_swapped;
if (!acn_if_list) return; /* nothing to do if the list is empty */
while (1) {
p1 = acn_if_list; /* start at the head of the list */
prev = 0;
has_swapped = 0;
while ((p2 = p1->next)) {
if (if_sort(p1->name, p2->name) > 0) {
if (prev) { /* we are swapping things that are _not_ at the head of the list */
temp = p2->next;
prev->next = p2;
p2->next = p1;
p1->next = temp;
} else { /* special treatment if we are swapping with the head of the list */
temp = p2->next;
acn_if_list= p2;
p2->next = p1;
p1->next = temp;
}
p1 = p2;
prev = p1;
has_swapped = 1;
}
prev = p1;
p1 = p1->next;
}
if (has_swapped == 0)
return;
}
return;
}
static int process_client_data (char *errbuf) { /* returns: -1 = error, 0 = OK */
int chassis, geoslot;
unit_t *u;
pcap_if_t *iff, *prev_iff;
pcap_addr_t *addr, *prev_addr;
char *ptr;
int address_count;
struct sockaddr_in *s;
char *newname;
bpf_u_int32 interfaceType;
unsigned char flags;
prev_iff = 0;
for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {
for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { /* now loop over all the devices */
u = &units[chassis][geoslot];
empty_unit_iface(u);
ptr = u->imsg; /* point to the start of the msg for this IOP */
while (ptr < (u->imsg + u->len)) {
if ((iff = malloc(sizeof(pcap_if_t))) == NULL) {
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
return -1;
}
memset((char *)iff, 0, sizeof(pcap_if_t)); /* bzero() is deprecated, replaced with memset() */
if (acn_if_list == 0) acn_if_list = iff; /* remember the head of the list */
if (prev_iff) prev_iff->next = iff; /* insert a forward link */
if (*ptr) { /* if there is a count for the name */
if ((iff->name = malloc(*ptr + 1)) == NULL) { /* get that amount of space */
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
return -1;
}
memcpy(iff->name, (ptr + 1), *ptr); /* copy the name into the malloc'ed space */
*(iff->name + *ptr) = 0; /* and null terminate the string */
ptr += *ptr; /* now move the pointer forwards by the length of the count plus the length of the string */
}
ptr++;
if (*ptr) { /* if there is a count for the description */
if ((iff->description = malloc(*ptr + 1)) == NULL) { /* get that amount of space */
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
return -1;
}
memcpy(iff->description, (ptr + 1), *ptr); /* copy the name into the malloc'ed space */
*(iff->description + *ptr) = 0; /* and null terminate the string */
ptr += *ptr; /* now move the pointer forwards by the length of the count plus the length of the string */
}
ptr++;
interfaceType = ntohl(*(bpf_u_int32 *)ptr);
ptr += 4; /* skip over the interface type */
flags = *ptr++;
if (flags) iff->flags = PCAP_IF_LOOPBACK; /* if this is a loopback style interface, lets mark it as such */
address_count = *ptr++;
prev_addr = 0;
while (address_count--) {
if ((addr = malloc(sizeof(pcap_addr_t))) == NULL) {
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
return -1;
}
+ memset((char *)addr, 0, sizeof(pcap_addr_t)); /* bzero() is deprecated, replaced with memset() */
if (iff->addresses == 0) iff->addresses = addr;
if (prev_addr) prev_addr->next = addr; /* insert a forward link */
if (*ptr) { /* if there is a count for the address */
if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) { /* get that amount of space */
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
return -1;
}
memset((char *)s, 0, sizeof(struct sockaddr_in)); /* bzero() is deprecated, replaced with memset() */
addr->addr = (struct sockaddr *)s;
s->sin_family = AF_INET;
s->sin_addr.s_addr = *(bpf_u_int32 *)(ptr + 1); /* copy the address in */
ptr += *ptr; /* now move the pointer forwards according to the specified length of the address */
}
ptr++; /* then forwards one more for the 'length of the address' field */
if (*ptr) { /* process any netmask */
if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) {
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
return -1;
}
/* bzero() is deprecated, replaced with memset() */
memset((char *)s, 0, sizeof(struct sockaddr_in));
addr->netmask = (struct sockaddr *)s;
s->sin_family = AF_INET;
s->sin_addr.s_addr = *(bpf_u_int32*)(ptr + 1);
ptr += *ptr;
}
ptr++;
if (*ptr) { /* process any broadcast address */
if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) {
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
return -1;
}
/* bzero() is deprecated, replaced with memset() */
memset((char *)s, 0, sizeof(struct sockaddr_in));
addr->broadaddr = (struct sockaddr *)s;
s->sin_family = AF_INET;
s->sin_addr.s_addr = *(bpf_u_int32*)(ptr + 1);
ptr += *ptr;
}
ptr++;
if (*ptr) { /* process any destination address */
if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) {
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
return -1;
}
/* bzero() is deprecated, replaced with memset() */
memset((char *)s, 0, sizeof(struct sockaddr_in));
addr->dstaddr = (struct sockaddr *)s;
s->sin_family = AF_INET;
s->sin_addr.s_addr = *(bpf_u_int32*)(ptr + 1);
ptr += *ptr;
}
ptr++;
prev_addr = addr;
}
prev_iff = iff;
newname = translate_IOP_to_pcap_name(u, iff->name, interfaceType); /* add a translation entry and get a point to the mangled name */
if ((iff->name = realloc(iff->name, strlen(newname) + 1)) == NULL) { /* we now re-write the name stored in the interface list */
snprintf(errbuf, PCAP_ERRBUF_SIZE, "realloc: %s", pcap_strerror(errno));
return -1;
}
strcpy(iff->name, newname); /* to this new name */
}
}
}
return 0;
}
static int read_client_data (int fd) {
unsigned char buf[256];
int chassis, geoslot;
unit_t *u;
int len;
find_unit_by_fd(fd, &chassis, &geoslot, &u);
if ((len = recv(fd, buf, sizeof(buf), 0)) <= 0) return 0; /* read in whatever data was sent to us */
if ((u->imsg = realloc(u->imsg, (u->len + len))) == NULL) /* extend the buffer for the new data */
return 0;
memcpy((u->imsg + u->len), buf, len); /* append the new data */
u->len += len;
return 1;
}
static void wait_for_all_answers(void) {
int retval;
struct timeval tv;
int fd;
int chassis, geoslot;
tv.tv_sec = 2;
tv.tv_usec = 0;
while (1) {
int flag = 0;
fd_set working_set;
for (fd = 0; fd <= max_fs; fd++) { /* scan the list of descriptors we may be listening to */
if (FD_ISSET(fd, &readfds)) flag = 1; /* and see if there are any still set */
}
if (flag == 0) return; /* we are done, when they are all gone */
memcpy(&working_set, &readfds, sizeof(readfds)); /* otherwise, we still have to listen for more stuff, till we timeout */
retval = select(max_fs + 1, &working_set, NULL, NULL, &tv);
if (retval == -1) { /* an error occured !!!!! */
return;
} else if (retval == 0) { /* timeout occured, so process what we've got sofar and return */
printf("timeout\n");
return;
} else {
for (fd = 0; fd <= max_fs; fd++) { /* scan the list of things to do, and do them */
if (FD_ISSET(fd, &working_set)) {
if (read_client_data(fd) == 0) { /* if the socket has closed */
FD_CLR(fd, &readfds); /* and descriptors we listen to for errors */
find_unit_by_fd(fd, &chassis, &geoslot, NULL);
close_with_IOP(chassis, geoslot, FIND); /* and close out connection to him */
}
}
}
}
}
}
static char *get_error_response(int fd, char *errbuf) { /* return a pointer on error, NULL on no error */
char byte;
int len = 0;
while (1) {
recv(fd, &byte, 1, 0); /* read another byte in */
if (errbuf && (len++ < PCAP_ERRBUF_SIZE)) { /* and if there is still room in the buffer */
*errbuf++ = byte; /* stick it in */
*errbuf = '\0'; /* ensure the string is null terminated just in case we might exceed the buffer's size */
}
if (byte == '\0') {
if (len > 1) { return errbuf; }
else { return NULL; }
}
}
}
int acn_findalldevs(char *errbuf) { /* returns: -1 = error, 0 = OK */
int chassis, geoslot;
unit_t *u;
FD_ZERO(&readfds);
max_fs = 0;
for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {
for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
u = &units[chassis][geoslot];
if (u->ip && (open_with_IOP(u, FIND))) { /* connect to the remote IOP */
send_to_fd(u->find_fd, 1, (unsigned char *)"\0");
if (get_error_response(u->find_fd, errbuf))
close_with_IOP(chassis, geoslot, FIND);
else {
if (u->find_fd > max_fs)
max_fs = u->find_fd; /* remember the highest number currently in use */
FD_SET(u->find_fd, &readfds); /* we are going to want to read this guy's response to */
u->len = 0;
send_to_fd(u->find_fd, 1, (unsigned char *)"Q"); /* this interface query request */
}
}
}
}
wait_for_all_answers();
if (process_client_data(errbuf))
return -1;
sort_if_table();
return 0;
}
static int pcap_stats_acn(pcap_t *handle, struct pcap_stat *ps) {
unsigned char buf[12];
send_to_fd(handle->fd, 1, (unsigned char *)"S"); /* send the get_stats command to the IOP */
if (read_client_nbytes(handle->fd, sizeof(buf), buf) == -1) return -1; /* try reading the required bytes */
ps->ps_recv = ntohl(*(uint32_t *)&buf[0]); /* break the buffer into its three 32 bit components */
ps->ps_drop = ntohl(*(uint32_t *)&buf[4]);
ps->ps_ifdrop = ntohl(*(uint32_t *)&buf[8]);
return 0;
}
static int acn_open_live(const char *name, char *errbuf, int *linktype) { /* returns 0 on error, else returns the file descriptor */
int chassis, geoslot;
unit_t *u;
iface_t *p;
pcap_if_t *alldevsp;
pcap_findalldevs_interfaces(&alldevsp, errbuf);
for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { /* scan the table... */
for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
u = &units[chassis][geoslot];
if (u->ip != NULL) {
p = u->iface;
while (p) { /* and all interfaces... */
if (p->IOPname && p->name && (strcmp(p->name, name) == 0)) { /* and if we found the interface we want... */
*linktype = p->iftype;
open_with_IOP(u, LIVE); /* start a connection with that IOP */
send_to_fd(u->fd, strlen(p->IOPname)+1, (unsigned char *)p->IOPname); /* send the IOP's interface name, and a terminating null */
if (get_error_response(u->fd, errbuf)) {
return -1;
}
return u->fd; /* and return that open descriptor */
}
p = p->next;
}
}
}
}
return -1; /* if the interface wasn't found, return an error */
}
static void acn_start_monitor(int fd, int snaplen, int timeout, int promiscuous, int direction) {
unsigned char buf[8];
unit_t *u;
//printf("acn_start_monitor()\n"); // fulko
find_unit_by_fd(fd, NULL, NULL, &u);
if (u->first_time == 0) {
buf[0] = 'M';
*(uint32_t *)&buf[1] = htonl(snaplen);
buf[5] = timeout;
buf[6] = promiscuous;
buf[7] = direction;
//printf("acn_start_monitor() first time\n"); // fulko
send_to_fd(fd, 8, buf); /* send the start monitor command with its parameters to the IOP */
u->first_time = 1;
}
//printf("acn_start_monitor() complete\n"); // fulko
}
static int pcap_inject_acn(pcap_t *p, const void *buf _U_, size_t size _U_) {
strlcpy(p->errbuf, "Sending packets isn't supported on ACN adapters",
PCAP_ERRBUF_SIZE);
return (-1);
}
static int pcap_setfilter_acn(pcap_t *handle, struct bpf_program *bpf) {
int fd = handle->fd;
int count;
struct bpf_insn *p;
uint16_t shortInt;
uint32_t longInt;
send_to_fd(fd, 1, (unsigned char *)"F"); /* BPF filter follows command */
count = bpf->bf_len;
longInt = htonl(count);
send_to_fd(fd, 4, (unsigned char *)&longInt); /* send the instruction sequence count */
p = bpf->bf_insns;
while (count--) { /* followed by the list of instructions */
shortInt = htons(p->code);
longInt = htonl(p->k);
send_to_fd(fd, 2, (unsigned char *)&shortInt);
send_to_fd(fd, 1, (unsigned char *)&p->jt);
send_to_fd(fd, 1, (unsigned char *)&p->jf);
send_to_fd(fd, 4, (unsigned char *)&longInt);
p++;
}
if (get_error_response(fd, NULL))
return -1;
return 0;
}
static int pcap_setdirection_acn(pcap_t *handle, pcap_direction_t d) {
snprintf(handle->errbuf, sizeof(handle->errbuf),
"Setting direction is not supported on ACN adapters");
return -1;
}
static int acn_read_n_bytes_with_timeout(pcap_t *handle, int count) {
struct timeval tv;
int retval, fd;
fd_set r_fds;
fd_set w_fds;
u_char *bp;
int len = 0;
int offset = 0;
tv.tv_sec = 5;
tv.tv_usec = 0;
fd = handle->fd;
FD_ZERO(&r_fds);
FD_SET(fd, &r_fds);
memcpy(&w_fds, &r_fds, sizeof(r_fds));
bp = handle->bp;
while (count) {
retval = select(fd + 1, &w_fds, NULL, NULL, &tv);
if (retval == -1) { /* an error occured !!!!! */
// fprintf(stderr, "error during packet data read\n");
return -1; /* but we need to return a good indication to prevent unneccessary popups */
} else if (retval == 0) { /* timeout occured, so process what we've got sofar and return */
// fprintf(stderr, "timeout during packet data read\n");
return -1;
} else {
if ((len = recv(fd, (bp + offset), count, 0)) <= 0) {
// fprintf(stderr, "premature exit during packet data rx\n");
return -1;
}
count -= len;
offset += len;
}
}
return 0;
}
static int pcap_read_acn(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) {
#define HEADER_SIZE (4 * 4)
unsigned char packet_header[HEADER_SIZE];
struct pcap_pkthdr pcap_header;
//printf("pcap_read_acn()\n"); // fulko
acn_start_monitor(handle->fd, handle->snapshot, handle->opt.timeout, handle->opt.promisc, handle->direction); /* maybe tell him to start monitoring */
//printf("pcap_read_acn() after start monitor\n"); // fulko
handle->bp = packet_header;
if (acn_read_n_bytes_with_timeout(handle, HEADER_SIZE) == -1) return 0; /* try to read a packet header in so we can get the sizeof the packet data */
pcap_header.ts.tv_sec = ntohl(*(uint32_t *)&packet_header[0]); /* tv_sec */
pcap_header.ts.tv_usec = ntohl(*(uint32_t *)&packet_header[4]); /* tv_usec */
pcap_header.caplen = ntohl(*(uint32_t *)&packet_header[8]); /* caplen */
pcap_header.len = ntohl(*(uint32_t *)&packet_header[12]); /* len */
handle->bp = handle->buffer + handle->offset; /* start off the receive pointer at the right spot */
if (acn_read_n_bytes_with_timeout(handle, pcap_header.caplen) == -1) return 0; /* then try to read in the rest of the data */
callback(user, &pcap_header, handle->bp); /* call the user supplied callback function */
return 1;
}
static int pcap_activate_sita(pcap_t *handle) {
int fd;
if (handle->opt.rfmon) {
/*
* No monitor mode on SITA devices (they're not Wi-Fi
* devices).
*/
return PCAP_ERROR_RFMON_NOTSUP;
}
/* Initialize some components of the pcap structure. */
handle->inject_op = pcap_inject_acn;
handle->setfilter_op = pcap_setfilter_acn;
handle->setdirection_op = pcap_setdirection_acn;
handle->set_datalink_op = NULL; /* can't change data link type */
handle->getnonblock_op = pcap_getnonblock_fd;
handle->setnonblock_op = pcap_setnonblock_fd;
handle->cleanup_op = pcap_cleanup_acn;
handle->read_op = pcap_read_acn;
handle->stats_op = pcap_stats_acn;
fd = acn_open_live(handle->opt.source, handle->errbuf,
&handle->linktype);
if (fd == -1)
return PCAP_ERROR;
handle->fd = fd;
handle->bufsize = handle->snapshot;
/* Allocate the buffer */
handle->buffer = malloc(handle->bufsize + handle->offset);
if (!handle->buffer) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"malloc: %s", pcap_strerror(errno));
pcap_cleanup_acn(handle);
return PCAP_ERROR;
}
/*
* "handle->fd" is a socket, so "select()" and "poll()"
* should work on it.
*/
handle->selectable_fd = handle->fd;
return 0;
}
pcap_t *pcap_create_interface(const char *device, char *ebuf) {
pcap_t *p;
p = pcap_create_common(device, ebuf, 0);
if (p == NULL)
return (NULL);
p->activate_op = pcap_activate_sita;
return (p);
}
Jump to Line
Something went wrong with that request. Please try again.