/* * etherhelpertool.c - Reads and writes raw ethernet packets usng bpf * interface. * * Copyright (C) 2010, Daniel Sumorok * * Basilisk II (C) 1997-2008 Christian Bauer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define STR_MAX 256 #define MAX_ARGV 10 static int remove_bridge = 0; static char bridge_name[STR_MAX]; static const char *exec_name = "etherhelpertool"; static int main_loop(int sd, int use_bpf); static int open_tap(char *ifname); static int run_cmd(const char *cmd); static void handler(int signum); static int install_signal_handlers(void); static void do_exit(void); static int open_bpf(char *ifname); int main(int argc, char **argv) { char *if_name; int ret = 255; int sd = -1; int tapNum; int use_bpf; if (argc != 2) { return 255; } if_name = argv[1]; do { if (strncmp(if_name, "tap", 3) == 0) { sd = open_tap(if_name); use_bpf = 0; } else { sd = open_bpf(if_name); use_bpf = 1; } if (sd < 0) { fprintf(stderr, "%s: open device failed.\n", exec_name); ret = 253; break; } if (install_signal_handlers() != 0) { fprintf(stderr, "%s: failed to install signal handers.\n", exec_name); ret = 252; break; } ret = main_loop(sd, use_bpf); close(sd); } while (0); do_exit(); return ret; } static int main_loop(int sd, int use_bpf) { fd_set readSet; char *outgoing, *incoming; unsigned short *out_len; unsigned short *in_len; int in_index, out_index; u_int blen = 0; int ret; int fret = 0; int pkt_len; int frame_len; int pad; char c = 0; blen = 4096; incoming = malloc(blen); if (incoming == NULL) { fprintf(stderr, "%s: malloc() failed.\n", exec_name); return -2; } outgoing = malloc(blen); if (outgoing == NULL) { free(incoming); fprintf(stderr, "%s: malloc() failed.\n", exec_name); return -3; } in_index = 0; out_index = 0; out_len = (unsigned short *)outgoing; /* Let our parent know we are ready for business. */ if(write(0, &c, 1) != 1) { fprintf(stderr, "%s: Failed to notify main application: %s\n", __func__, strerror(errno)); } while (1) { int i; FD_ZERO(&readSet); FD_SET(0, &readSet); FD_SET(sd, &readSet); ret = select(sd + 1, &readSet, NULL, NULL, NULL); if (ret < 0) { fprintf(stderr, "%s: select() failed.\n", exec_name); fret = -4; break; } if (FD_ISSET(0, &readSet)) { if (out_index < 2) { ret = read(0, outgoing + out_index, 2-out_index); } else { ret = read(0, outgoing + out_index, *out_len - out_index + 2); } if (ret < 1) { if(ret < 0) { fprintf(stderr, "%s: read() failed.\n", exec_name); } fret = -5; break; } out_index += ret; if (out_index > 1) { if ((*out_len + 2) > blen) { fret = -6; break; } if (out_index == (*out_len + 2)) { if(use_bpf) { ret = write(sd, out_len + 1, *out_len); if (ret != *out_len) { fprintf(stderr, "%s: write() failed.\n", exec_name); fret = -7; break; } } else { ret = write(sd, out_len + 1, *out_len); if (ret != *out_len) { fprintf(stderr, "%s: write() failed.\n", exec_name); fret = -7; break; } } out_index = 0; } } } if (FD_ISSET(sd, &readSet)) { in_len = (unsigned short *)incoming; pkt_len = read(sd, in_len + 1, blen-2); if (pkt_len < 14) { fprintf(stderr, "%s: read() returned %d.\n", exec_name, pkt_len); fret = -8; break; } *in_len = pkt_len; if (write(0, in_len, pkt_len + 2) < (pkt_len + 2)) { fprintf(stderr, "%s: write() failed\n", exec_name); fret = -10; break; } } } free(incoming); free(outgoing); return fret; } static int open_tap(char *ifname) { char str[STR_MAX] = {0}; char ifstr[STR_MAX] = {0}; char *interface; char *address = NULL; char *netmask = NULL; char *bridge = NULL; char *bridged_if = NULL; int sd; struct ifreq ifr = {0}; snprintf(ifstr, STR_MAX, "%s", ifname); interface = strtok(ifstr, "/"); bridge = strtok(NULL, "/"); if (bridge != NULL) { bridged_if = strtok(NULL, "/"); } interface = strtok(ifstr, ":"); address = strtok(NULL, ":"); if (address != NULL) { netmask = strtok(NULL, ":"); } sd = open("/dev/net/tun", O_RDWR); if (sd < 0) { fprintf(stderr, "%s: Failed to open %s\n", exec_name, interface); return -1; } snprintf(str, STR_MAX, "/dev/%s", interface); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strncpy(ifr.ifr_name, interface, IFNAMSIZ); if(ioctl(sd, TUNSETIFF, (void *)&ifr) != 0) { fprintf(stderr, "%s: ioctl(TUNSETIFF): %s\n", __func__, strerror(errno)); close(sd); return -1; } if (address == NULL) { snprintf(str, STR_MAX, "/sbin/ifconfig %s up", interface); } else if (netmask == NULL) { snprintf(str, STR_MAX, "/sbin/ifconfig %s %s", interface, address); } else { snprintf(str, STR_MAX, "/sbin/ifconfig %s %s netmask %s", interface, address, netmask); } if (run_cmd(str) != 0) { fprintf(stderr, "%s: Failed to configure %s\n", exec_name, interface); close(sd); return -1; } if (bridge != NULL) { /* Check to see if bridge is alread up */ snprintf(str, STR_MAX, "/sbin/ifconfig %s", bridge); if (run_cmd(str) == 0) { /* bridge is already up */ if (bridged_if != NULL) { fprintf(stderr, "%s: Warning: %s already exists, so %s was not added.\n", exec_name, bridge, bridged_if); } } else { snprintf(str, STR_MAX, "/sbin/brctl addbr %s", bridge); if (run_cmd(str) != 0) { fprintf(stderr, "%s: Failed to create %s\n", exec_name, bridge); close(sd); return -1; } remove_bridge = 1; strncpy(bridge_name, bridge, STR_MAX); snprintf(str, STR_MAX, "/sbin/ifconfig %s up", bridge); if (run_cmd(str) != 0) { fprintf(stderr, "%s: Failed to open %s\n", exec_name, bridge); close(sd); return -1; } if (bridged_if != NULL) { snprintf(str, STR_MAX, "/sbin/brctl addif %s %s", bridge, bridged_if); if (run_cmd(str) != 0) { fprintf(stderr, "%s: Failed to add %s to %s\n", exec_name, bridged_if, bridge); close(sd); return -1; } } snprintf(str, STR_MAX, "/sbin/brctl addif %s %s", bridge, interface); if (run_cmd(str) != 0) { fprintf(stderr, "%s: Failed to add %s to %s\n", exec_name, interface, bridge); close(sd); return -1; } } } return sd; } static int run_cmd(const char *cmd) { char cmd_buffer[STR_MAX] = {0}; char *argv[MAX_ARGV + 1] = {0}; int i; pid_t pid, waitpid; int status = 0; /* Collect arguments */ strncpy(cmd_buffer, cmd, STR_MAX-1); argv[0] = strtok(cmd_buffer, " "); for (i=1; i