📄 uml_netjig.c
字号:
/* * @(#) jig to exercise a UML/FreeSWAN kernel with two interfaces * * Copyright (C) 2001 Michael Richardson <mcr@freeswan.org> * * 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. See <http://www.fsf.org/copyleft/gpl.txt>. * * 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. * * RCSID $Id: uml_netjig.c,v 1.2 2002/11/05 01:51:44 ken Exp $ * * @(#) based upon uml_router from User-Mode-Linux tools package * *//* * This file contains a program to excersize a FreeSWAN kernel that is * built in a User-Mode-Linux form. It creates four sets of Unix * domain sockets: two control sockets and two data sockets. * * These sockets make up the connection points for the "daemon" method * of networking provided by UML. * * The first connection is intended to connect to "eth0" (the inside * or "private" network) and the second one to "eth1" (the outside or * "public" network). * * Packets are fed into one network interface from a (pcap) capture file and * are captured from the other interface into a pcap capture file. * * The program can take an argument which is a script/program to run * with the appropriate UML arguments. This can be the UML kernel * itself, a script that invokes it or something that just records * things. * * The environment variables UML_{public,private}_{CTL,DATA} are set to * the names of the respective sockets. * * If the --arp option is given, the program will respond to all ARP * requests that it sees, providing a suitable response. * * Note that the program continues to operate as a switch and will * accept multiple connections. All packets are logged and the * outgoing packets are sent to wherever the destination MAC address * specifies. * */#include <sys/stat.h>#include <sys/types.h>#include <stdio.h>#include <stddef.h>#include <stdlib.h>#include <fcntl.h>#include <unistd.h>#include <errno.h>#include <signal.h>#include <sys/socket.h>#include <sys/un.h>#include <netinet/in.h>#include <net/ethernet.h>#include <net/if_arp.h>#define _GNU_SOURCE 1#include <getopt.h>#include "pcap.h"#include <sys/queue.h>#define ETH_ALEN 6#define MAX(x,y) ((x) > (y) ? (x) : (y))#ifdef NETDISSECT#include "netdissect.h"struct netdissect_options gndo;int tcpdump_print = 1;#endifstruct connection { TAILQ_ENTRY(connection) link; int active; int control; struct sockaddr_un name; unsigned char addr[ETH_ALEN];};enum request_type { REQ_NEW_CONTROL };struct request { enum request_type type; union { struct { unsigned char addr[ETH_ALEN]; struct sockaddr_un name; } new_control; struct { unsigned long cookie; } new_data; } u;};struct packet { struct { unsigned char dest[6]; unsigned char src[6]; u_int16_t proto; } header; unsigned char data[1500];};struct nethub { TAILQ_HEAD(,connection) connections; char *nh_name; unsigned char nh_defaultether[6]; struct in_addr nh_defaultgate; int nh_allarp; char *nh_outputFile; pcap_dumper_t *nh_output; char *nh_inputFile; pcap_t *nh_input; char *ctl_socket_name; int ctl_listen_fd; char *data_socket_name; int data_fd;};struct nethub public, private;static fd_set perm_fds;static int max_fd = -1;static char *progname;void *xmalloc1(size_t size, char *file, int linenum){ void *space; space = malloc(size); if(space == NULL) { fprintf(stderr, "no memory allocating %d bytes at %s:%d\n", size, file, linenum); exit(1); } return space;}#define xmalloc(X) xmalloc1((X), __FILE__, __LINE__)static void cleanup(struct nethub *nh){ if(unlink(nh->ctl_socket_name) < 0){ printf("Couldn't remove control socket '%s' : %s\n", nh->ctl_socket_name, strerror(errno)); } if(unlink(nh->data_socket_name) < 0){ printf("Couldn't remove data socket '%s' : %s\n", nh->data_socket_name, strerror(errno)); }}static void sig_handler(int sig){ printf("Caught signal %d, cleaning up and exiting\n", sig); cleanup(&public); cleanup(&private); signal(sig, SIG_DFL); kill(getpid(), sig);}static void close_descriptor(int fd){ FD_CLR(fd, &perm_fds); close(fd);}static void free_connection(struct nethub *nh, struct connection *conn){ close_descriptor(conn->control); FD_CLR(conn->control, &perm_fds); TAILQ_REMOVE(&nh->connections, conn, link); free(conn);}static void service_connection(struct nethub *nh, struct connection *conn){ struct request req; int n; n = read(conn->control, &req, sizeof(req)); if(n < 0){ perror("Reading request"); free_connection(nh, conn); return; } else if(n == 0){ printf("%s: disconnect from hw address %02x:%02x:%02x:%02x:%02x:%02x\n", nh->nh_name, conn->addr[0], conn->addr[1], conn->addr[2], conn->addr[3], conn->addr[4], conn->addr[5]); free_connection(nh, conn); return; } switch(req.type){ case REQ_NEW_CONTROL: memcpy(conn->addr, req.u.new_control.addr, sizeof(conn->addr)); conn->name = req.u.new_control.name; conn->active = 1; printf("%s: new connection - hw address %02x:%02x:%02x:%02x:%02x:%02x\n", nh->nh_name, conn->addr[0], conn->addr[1], conn->addr[2], conn->addr[3], conn->addr[4], conn->addr[5]); break; default: printf("Bad request type : %d\n", req.type); free_connection(nh, conn); }}static int match_addr(unsigned char *host, unsigned char *packet){ if(packet[0] & 1) return(1); return((packet[0] == host[0]) && (packet[1] == host[1]) && (packet[2] == host[2]) && (packet[3] == host[3]) && (packet[4] == host[4]) && (packet[5] == host[5]));}static void forward_data(struct nethub *nh, struct packet *p, int len){ struct connection *c, *next; for(c = nh->connections.tqh_first; c != NULL; c = next){ next = c->link.tqe_next; if(c->active && match_addr(c->addr, p->header.dest)){ sendto(nh->data_fd, p, len, 0, (struct sockaddr *) &c->name, sizeof(c->name)); } }}static void handle_data(struct nethub *nh){ struct pcap_pkthdr ph; struct packet p; int len; len = recvfrom(nh->data_fd, &p, sizeof(p), 0, NULL, 0); if(len < 0){ if(errno != EAGAIN) perror("Reading data"); return; } memset(&ph, 0, sizeof(ph)); ph.caplen = len; ph.len = len; if(nh->nh_outputFile) { pcap_dump((u_char *)nh->nh_output, &ph, (u_char *)&p); }#ifdef NETDISSECT /* now dump it to tcpdump dissector if one was configured */ if(tcpdump_print) { printf("%8s:", nh->nh_name); ether_if_print((u_char *)&gndo, &ph, (u_char *)&p); }#endif#ifdef ARP_PROCESS if(nh->nh_defaultgate.s_addr!=0 || nh->nh_allarp) { if(p.header.proto == htons(ETHERTYPE_ARP)) { struct arphdr *ahdr; ahdr = (struct arphdr *)&p.data; if(ahdr->ar_hrd == htons(ARPHRD_ETHER) && ahdr->ar_pro == htons(ETHERTYPE_IP) && ahdr->ar_hln == ETH_ALEN && ahdr->ar_pln == 4 && ahdr->ar_op == htons(ARPOP_REQUEST)) { u_int32_t *tip; u_int32_t *sip; sip = (u_int32_t *)(p.data + /*sizeof(arphdr)*/8 + 1*ETH_ALEN); tip = (u_int32_t *)(p.data + /*sizeof(arphdr)*/8 + 2*ETH_ALEN + 4); if(nh->nh_allarp == 1 || *tip == nh->nh_defaultgate.s_addr) { /* AHA! reply to ARP request */ /* we mutate this packet in place */ /* change this to a reply */ ahdr->ar_op = htons(ARPOP_REPLY); /* swap ether fields */ memcpy(p.header.dest, p.header.src, ETH_ALEN); memcpy(p.data + 8, nh->nh_defaultether, ETH_ALEN); memcpy(p.header.src, nh->nh_defaultether, ETH_ALEN); /* swap ip fields */ { uint32_t tmp; tmp=*sip; *sip=*tip; *tip=tmp; } printf("%s: found ARP request, replying: \n", nh->nh_name);#ifdef NETDISSECT if(tcpdump_print) { struct pcap_pkthdr ph; memset(&ph, 0, sizeof(ph)); ph.caplen = len; ph.len = len; printf("%8s:", nh->nh_name); ether_if_print((u_char *)&gndo, &ph, (u_char *)&p); }#endif } } } }#endif forward_data(nh, &p, len);}static void new_connection(struct nethub *nh, int fd){ struct connection *conn; conn = xmalloc(sizeof(struct connection)); if(conn == NULL){ perror("malloc"); close_descriptor(fd); return; } conn->control = fd; conn->active = 0; conn->addr[0]=0xff; TAILQ_INSERT_TAIL(&nh->connections, conn, link);}void handle_connections(struct nethub *nh, fd_set *fds, int max){ struct connection *c; int i; for(i=0;i<max;i++){ if(FD_ISSET(i, fds)){ for(c = nh->connections.tqh_first; c != NULL; c = c->link.tqe_next) { if(c->control == i){ service_connection(nh, c); break; } } } }}void accept_connection(struct nethub *nh){ struct sockaddr addr; int len, new; new = accept(nh->ctl_listen_fd, &addr, &len); if(new < 0){ perror("accept"); return; } if(fcntl(new, F_SETFL, O_NONBLOCK) < 0){ perror("fcntl - setting O_NONBLOCK"); close(new); return; } if(new > max_fd) max_fd = new; FD_SET(new, &perm_fds); new_connection(nh, new);}int still_used(struct sockaddr_un *sun){ int test_fd, ret = 1; if((test_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){ perror("socket"); exit(1); } if(connect(test_fd, (struct sockaddr *) sun, sizeof(*sun)) < 0){ if(errno == ECONNREFUSED){ if(unlink(sun->sun_path) < 0){ fprintf(stderr, "Failed to removed unused socket '%s': ", sun->sun_path); perror(""); } ret = 0; } else perror("connect"); } close(test_fd); return(ret);}int bind_socket(int fd, const char *name){ struct sockaddr_un sun; sun.sun_family = AF_UNIX; strcpy(sun.sun_path, name); if(bind(fd, (struct sockaddr *) &sun, sizeof(sun)) < 0){ if((errno == EADDRINUSE) && still_used(&sun)) return(EADDRINUSE); else if(bind(fd, (struct sockaddr *) &sun, sizeof(sun)) < 0){ perror("bind"); return(EPERM); } } return(0);}void bind_sockets(struct nethub *nh){ int ctl_err, ctl_present = 0, ctl_used = 0; int data_err, data_present = 0, data_used = 0; int try_remove_ctl, try_remove_data; ctl_err = bind_socket(nh->ctl_listen_fd, nh->ctl_socket_name); if(ctl_err != 0) ctl_present = 1; if(ctl_err == EADDRINUSE) ctl_used = 1; data_err = bind_socket(nh->data_fd, nh->data_socket_name); if(data_err != 0) data_present = 1; if(data_err == EADDRINUSE) data_used = 1; if(!ctl_err && !data_err) return; unlink(nh->ctl_socket_name); unlink(nh->data_socket_name); try_remove_ctl = ctl_present; try_remove_data = data_present; if(ctl_present && ctl_used){ fprintf(stderr, "The control socket '%s' has another server " "attached to it\n", nh->ctl_socket_name); try_remove_ctl = 0; } else if(ctl_present && !ctl_used) fprintf(stderr, "The control socket '%s' exists, isn't used, but couldn't " "be removed\n", nh->ctl_socket_name); if(data_present && data_used){ fprintf(stderr, "The data socket '%s' has another server " "attached to it\n", nh->data_socket_name); try_remove_data = 0; } else if(data_present && !data_used) fprintf(stderr, "The data socket '%s' exists, isn't used, but couldn't " "be removed\n", nh->data_socket_name); if(try_remove_ctl || try_remove_data){ fprintf(stderr, "You can either\n"); if(try_remove_ctl && !try_remove_data) fprintf(stderr, "\tremove '%s'\n", nh->ctl_socket_name); else if(!try_remove_ctl && try_remove_data) fprintf(stderr, "\tremove '%s'\n", nh->data_socket_name); else fprintf(stderr, "\tremove '%s' and '%s'\n", nh->ctl_socket_name, nh->data_socket_name); fprintf(stderr, "\tor rerun with different, unused filenames for " "sockets:\n"); fprintf(stderr, "\t\t%s -unix <control> <data>\n", progname); fprintf(stderr, "\t\tand run the UMLs with " "'eth0=daemon,,unix,<control>,<data>\n"); exit(1); } else { fprintf(stderr, "You should rerun with different, unused filenames for " "sockets:\n"); fprintf(stderr, "\t%s -unix <control> <data>\n", progname); fprintf(stderr, "\tand run the UMLs with " "'eth0=daemon,,unix,<control>,<data>'\n"); exit(1); }}static void Usage(void){ fprintf(stderr, "Usage : uml_netjig \n" "Version $Revision: 1.2 $ \n\n"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -