⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nethub.c

📁 This a good VPN source
💻 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: nethub.c,v 1.10 2002/08/30 01:37:35 mcr Exp $ * * @(#) based upon uml_router from User-Mode-Linux tools package by Jeff Dike. * */#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 <assert.h>#include <setjmp.h>#include <sys/socket.h>#include <poll.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>#include "port.h"#include "hash.h"#ifdef NETDISSECT#include "netdissect.h"struct netdissect_options gndo;int tcpdump_print = 1;#endif#include "nethub.h"#include "netjig.h"void cleanup_nh(struct nethub *nh){  if(nh->pid_file_name) {    if(unlink(nh->pid_file_name) < 0 && errno!=ENOENT) {      fprintf(stderr, "Could not remove pid file '%s' : %s\n",	      nh->ctl_socket_name, strerror(errno));    }    free(nh->pid_file_name);    nh->pid_file_name = NULL;  }  if(nh->ctl_socket_name) {    if(unlink(nh->ctl_socket_name) < 0){      fprintf(stderr, "Couldn't remove control socket '%s' : %s\n",	      nh->ctl_socket_name, strerror(errno));    }    free(nh->ctl_socket_name);    nh->ctl_socket_name=NULL;  }  if(nh->ctl_listen_fd > 0) {    close(nh->ctl_listen_fd);    nh->ctl_listen_fd = -1;  }  if(nh->data_socket_name) {    if(nh->data_socket_name!=NULL && unlink(nh->data_socket_name) < 0){      fprintf(stderr, "Couldn't remove data socket '%s' : %s\n",	      nh->data_socket_name, strerror(errno));    }    free(nh->data_socket_name);    nh->data_socket_name=NULL;  }  if(nh->data_fd > 0) {    close(nh->data_fd);    nh->data_fd = -1;  }      if(nh->socket_dir != NULL && rmdir(nh->socket_dir) < 0) {    fprintf(stderr, "Couldn't remove socket dir '%s' : %s\n",	    nh->socket_dir, strerror(errno));  }  if(nh->nh_output) {    pcap_dump_close(nh->nh_output);    nh->nh_output=NULL;  }  if(nh->nh_outputFile) {    free(nh->nh_outputFile);    nh->nh_outputFile = NULL;  }  if(nh->nh_input) {    pcap_close(nh->nh_input);    nh->nh_input=NULL;  }  if(nh->nh_inputFile) {    free(nh->nh_inputFile);    nh->nh_inputFile = NULL;  }  /* XXX should free up hash entries and ports */  free(nh);}void add_fd(struct netjig_state *ns,	    int fd){  struct pollfd *p;  int i;  /*  fprintf(stderr, "Adding fd %d\n", fd); */  if(ns->nfds == ns->max_fds){    ns->max_fds = ns->max_fds ? 2 * ns->max_fds : 4;    if((ns->fds = realloc(ns->fds, ns->max_fds * sizeof(struct pollfd))) == NULL){      perror("realloc");      /* XXX need a better cleanup function ! */      exit(1);    }  }  p = &ns->fds[ns->nfds++];  p->fd = fd;  p->events = POLLIN;  p->revents=0;  /*   * assuming that FD's are small integers is very Unix.   * If you port this to WinBLOWs, well, sorry, figure out someone else.   */  while(fd >= ns->fd_array_size) {    ns->fd_array_size = ns->fd_array_size ? 2*ns->fd_array_size : 4;    if((ns->fd_array = realloc(ns->fd_array,			       ns->fd_array_size * sizeof(int))) ==NULL) {      perror("realloc fd_array");      /* XXX need a better cleanup function ! */      exit(1);    }  }  /* we rebuild the fd->pollfd mapping here because we might have reallocated   * it above, and recalculating it is pretty easy.   */  for(i=0; i < ns->fd_array_size; i++) {    ns->fd_array[i]=-1;  }  for(i=0, p=ns->fds; i < ns->nfds; i++, p++) {    /* fprintf(stderr, "Mapping fd:%d to item %d\n", p->fd, i); */    ns->fd_array[p->fd]=i;  }}void remove_fd(struct netjig_state *ns,		      int fd){  int i;  for(i = 0; i < ns->nfds; i++){    if(ns->fds[i].fd == fd) break;  }  if(i == ns->nfds){    fprintf(stderr, "remove_fd : Couldn't find descriptor %d\n", fd);  }  memmove(&ns->fds[i], &ns->fds[i + 1], (ns->max_fds - i - 1) * sizeof(struct pollfd));  ns->nfds--;  if(fd < ns->fd_array_size) {    ns->fd_array[fd]=-1;  }}void close_descriptor(struct netjig_state *ns,		      struct nethub       *nh,		      int fd){  remove_fd(ns, fd);  close(fd);  close_port(ns, nh, fd);}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 *sock_out){  struct sockaddr_un sun;  memset(&sun, 0, sizeof(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);    }  }  if(sock_out != NULL) *sock_out = sun;  return(0);}void bind_sockets_v0(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, NULL);  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, &nh->data_sun);  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);  }}void bind_data_socket(int fd, struct sockaddr_un *sun){  struct {    char zero;    int pid;    int usecs;  } name;  struct timeval tv;  name.zero = 0;  name.pid = getpid();  gettimeofday(&tv, NULL);  name.usecs = tv.tv_usec;  sun->sun_family = AF_UNIX;  memcpy(sun->sun_path, &name, sizeof(name));  if(bind(fd, (struct sockaddr *) sun, sizeof(*sun)) < 0){    perror("Binding to data socket");    exit(1);  }}void bind_sockets(struct nethub *nh){  int err, used;  err = bind_socket(nh->ctl_listen_fd, nh->ctl_socket_name, NULL);  if(err == 0){    bind_data_socket(nh->data_fd, &nh->data_sun);    return;  }  else if(err == EADDRINUSE) used = 1;    if(used){    fprintf(stderr, "The control socket '%s' has another server "	    "attached to it\n", nh->ctl_socket_name);    fprintf(stderr, "You can either\n");    fprintf(stderr, "\tremove '%s'\n", nh->ctl_socket_name);    fprintf(stderr, "\tor rerun with a different, unused filename for a "	    "socket\n");  }  else    fprintf(stderr, "The control socket '%s' exists, isn't used, but couldn't "	    "be removed\n", nh->ctl_socket_name);  exit(1);}#ifdef NETDISSECT/* Like default_print() but data need not be aligned */voiddefault_print_unaligned(struct netdissect_options *ipdo,			register const u_char *cp, register u_int length){	register u_int i, s;	register int nshorts;	if (ipdo->ndo_Xflag) {		ascii_print(ipdo, cp, length);		return;	}	nshorts = (u_int) length / sizeof(u_short);	i = 0;	while (--nshorts >= 0) {		if ((i++ % 8) == 0)			(void)fprintf(stderr, "\n\t\t\t");		s = *cp++;		(void)fprintf(stderr, " %02x%02x", s, *cp++);	}	if (length & 1) {		if ((i % 8) == 0)			(void)fprintf(stderr, "\n\t\t\t");		(void)fprintf(stderr, " %02x", *cp);	}}/* * By default, print the packet out in hex. */voiddefault_print(struct netdissect_options *ndo,	      register const u_char *bp, register u_int length){	default_print_unaligned(ndo, bp, length);}#endifstruct nethub *init_nethub(struct netjig_state *ns,			   char *switchname,			   char *data_socket,			   char *ctl_socket,			   int compat_v0){	int one;	char *env;	char *newdir, *p;	struct nethub *nh;	int used_base_dir;	one = 1;	used_base_dir = 0;	nh=xmalloc(sizeof(*nh));	memset(nh, 0, sizeof(*nh));	TAILQ_INIT(&nh->nh_ports);	nh->nh_name = strdup(switchname);	/* setup ARP stuff */	nh->nh_allarp = 0;		nh->nh_defaultgate.s_addr = 0;		nh->nh_defaultether[0]=0x10;	nh->nh_defaultether[1]=0x00;	nh->nh_defaultether[2]=0x00;	nh->nh_defaultether[3]=switchname[0];	nh->nh_defaultether[4]=switchname[1];	nh->nh_defaultether[5]=switchname[2];	if(ctl_socket == NULL) {	  /* cons up the names, and stick them in the environment */	  env = xmalloc(sizeof("UML_")+2*strlen(switchname)+sizeof("CTL=")+			strlen(ns->socketbasedir)+sizeof("/ctl")+4);	  	  sprintf(env, "UML_%s_CTL=%s/%s/ctl", switchname,		  ns->socketbasedir, switchname);	  putenv(env);	  nh->ctl_socket_name_env = env;	  nh->ctl_socket_name = strdup(strchr(env, '=')+1);	  used_base_dir = 1;	} else {	  nh->ctl_socket_name_env = NULL;	  nh->ctl_socket_name = strdup(ctl_socket);	}	if(data_socket == NULL) {	  env = xmalloc(sizeof("UML_")+2*strlen(switchname)+sizeof("DATA=")+			strlen(ns->socketbasedir)+sizeof("/data")+4);	  	  sprintf(env, "UML_%s_DATA=%s/%s/data", switchname,		  ns->socketbasedir, switchname);	  putenv(env);	  nh->data_socket_name_env = env;	  nh->data_socket_name = strdup(strchr(env, '=')+1);	  used_base_dir = 1;	} else {	  nh->data_socket_name_env = NULL;	  nh->data_socket_name = strdup(data_socket);	}	  	/* now make the directory, if we need it */ 	if(used_base_dir ) {		FILE *pidfile;		if(mkdir(ns->socketbasedir,0700) < 0 &&		   errno != EEXIST) {			perror(ns->socketbasedir);			exit(1);		}		newdir=strdup(nh->ctl_socket_name);		if((p=strrchr(newdir, '/'))!=NULL) {			*p='\0';			if(mkdir(newdir, 0700) < 0 &&			   errno != EEXIST) {				perror(newdir);				exit(1);			}		}		nh->socket_dir=newdir;		nh->pid_file_name=xmalloc(strlen(nh->socket_dir)+sizeof("pid")+2);		sprintf(nh->pid_file_name, "%s/pid", nh->socket_dir);		if((pidfile=fopen(nh->pid_file_name, "w"))==NULL) {			perror(nh->pid_file_name);		} else {			fprintf(pidfile, "%d", getpid());			fclose(pidfile);		}	} 	if((nh->ctl_listen_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){		perror("socket");		exit(1);	}	if(setsockopt(nh->ctl_listen_fd,		      SOL_SOCKET, SO_REUSEADDR, (char *) &one, 		      sizeof(one)) < 0){		perror("setsockopt");		exit(1);	}	if(fcntl(nh->ctl_listen_fd, F_SETFL, O_NONBLOCK) < 0){		perror("Setting O_NONBLOCK on connection fd");		exit(1);	}		if((nh->data_fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0){		perror("socket");		exit(1);	}#if 0	if(fcntl(nh->data_fd, F_SETFL, O_NONBLOCK) < 0){		perror("Setting O_NONBLOCK on data fd");		exit(1);	}#endif	if(compat_v0) bind_sockets_v0(nh);	else bind_sockets(nh);	if(listen(nh->ctl_listen_fd, 15) < 0){		perror("listen");		exit(1);	}	 	add_fd(ns, nh->ctl_listen_fd);	add_fd(ns, nh->data_fd);	hash_init(nh);	TAILQ_INSERT_TAIL(&ns->switches, nh, nh_link);	return nh;}struct nethub *find_nethubbyname(struct netjig_state *ns,				 char *name){  struct nethub *nh;  for(nh=ns->switches.tqh_first;      nh;      nh=nh->nh_link.tqe_next) {    if(strcasecmp(nh->nh_name, name)==0) {      break;    }  }  return nh;}void create_socket_dir(struct netjig_state *ns){	char tmpbuf[1024];	if(ns->socketbasedir == NULL) {		char *tmpdir_env;		int   fd_file;		tmpdir_env = getenv("TMPDIR");		if(tmpdir_env == NULL) {			tmpdir_env = P_tmpdir;		}		snprintf(tmpbuf, sizeof(tmpbuf)-4, "%s/umlXXXXXX", tmpdir_env);		fd_file = mkstemp(tmpbuf);				if(fd_file == -1) {			fprintf(stderr, "failed to make tmpdir (last=%s)\n", tmpbuf);			exit(1);		}		strcat(tmpbuf,".d");		if(mkdir(tmpbuf, 0700) != 0) {			fprintf(stderr, "failed to mkdir(%s): %s\n",				tmpbuf, strerror(errno));			exit(2);		}		ns->socketbasedir=strdup(tmpbuf);		close(fd_file);	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -