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

📄 port.c

📁 This a good VPN source
💻 C
字号:
/* * @(#) jig to exercise a UML/FreeSWAN kernel with two interfaces * * Copyright (C) 2001 Jeff Dike Jeff Dike <jdike@karaya.com> * 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: port.c,v 1.16 2003/04/07 02:43:22 mcr Exp $ * * @(#) based upon uml_router from User-Mode-Linux tools package by Jeff Dike. * */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <sys/socket.h>#include <sys/un.h>#include <sys/queue.h>#include <net/if_arp.h>#include <netinet/in.h>#include <poll.h>#include "pcap.h"#include "hash.h"#include "port.h"#include "nethub.h"struct port {	TAILQ_ENTRY(port) link;	int control;	void *data;	int data_len;	packet_sender sender;        unsigned char most_recent_ethernet[ETH_ALEN];};#define IS_BROADCAST(addr) ((addr[0] & 1) == 1)static void free_port(struct netjig_state *ns,		      struct nethub *nh,		      struct port *port){  TAILQ_REMOVE(&nh->nh_ports,port,link);  free(port);}void close_port(struct netjig_state *ns,		struct nethub *nh,		int fd){  struct port *port;  for(port = nh->nh_ports.tqh_first;      port != NULL;      port = port->link.tqe_next){    if(port->control == fd) break;  }  if(port == NULL){    fprintf(stderr, "No port associated with descriptor %d\n", fd);    return;  }  free_port(ns, nh, port);}static void update_src(struct netjig_state *ns,		       struct nethub       *nh,		       struct port *port,		       struct packet *p){  struct port *last;  /* We don't like broadcast source addresses */  if(IS_BROADCAST(p->header.src)) return;    last = find_in_hash(nh, p->header.src);  if(port != last){    /* old value differs from actual input port */    if(ns->verbose) {      fprintf(stderr,	      " Addr: %02x:%02x:%02x:%02x:%02x:%02x "	      " New port %d",	      p->header.src[0], p->header.src[1], p->header.src[2],	      p->header.src[3], p->header.src[4], p->header.src[5],	      port->control);    }    if(last != NULL){      if(ns->verbose) {	fprintf(stderr, "old port %d", last->control);      }      delete_hash(nh, p->header.src);    }    if(ns->verbose) {      fprintf(stderr, "\n");    }    memcpy(port->most_recent_ethernet, p->header.src, ETH_ALEN);    insert_into_hash(nh, p->header.src, port);  }  update_entry_time(nh, p->header.src);}static void send_dst(struct netjig_state *ns,		     struct nethub       *nh,		     struct port *srcport,		     struct packet *packet, int len, 		     int hub){  struct port *target, *p;  target = find_in_hash(nh, packet->header.dest);  if((target == NULL) || IS_BROADCAST(packet->header.dest) || hub){    if((target == NULL) && !IS_BROADCAST(packet->header.dest)){      if(ns->verbose) {	fprintf(stderr,		"hub %s unknown Addr: %02x:%02x:%02x:%02x:%02x:%02x from port %d\n",		nh->nh_name,		packet->header.src[0], packet->header.src[1], 		packet->header.src[2], packet->header.src[3], 		packet->header.src[4], packet->header.src[5],		(srcport == NULL) ? -1 : srcport->control);      }    }     /* no cache or broadcast/multicast == all ports */    for(p = nh->nh_ports.tqh_first;	p != NULL;	p = p->link.tqe_next){      /* don't send it back the port it came in */      if(p == srcport) continue;      /* don't send to ports that aren't initalized yet */      if(!p->sender) continue;      (*p->sender)(p->control, packet, len, p->data);    }  }  else (*target->sender)(target->control, packet, len, target->data);}void insert_data(struct netjig_state *ns,		 struct nethub *nh,		 struct packet *packet, int len){  send_dst(ns, nh, NULL, packet, len, nh->nh_hub);}void handle_data(struct netjig_state *ns,		 struct nethub *nh,		 struct packet *packet, int len,		 int   fd,		 void *data, int (*matcher)(int port_fd, int data_fd, 					    void *port_data,					    int port_data_len, 					    void *data)){  struct pcap_pkthdr ph;  struct port *p;  if(matcher) {	  for(p = nh->nh_ports.tqh_first;	      p != NULL;	      p = p->link.tqe_next){		  if((*matcher)(p->control, fd, p->data, p->data_len, data)) break;	  }  	  /* if we have an incoming port (we will unless the packet is inserted) */	  if(p != NULL) update_src(ns, nh, p, packet);  }  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 *)packet);  }#ifdef NETDISSECT  /* now dump it to tcpdump dissector if one was configured */  if(tcpdump_print) {    fprintf(stderr, "%8s:", nh->nh_name);    ether_if_print((u_char *)&gndo, &ph, (u_char *)packet);  }#endif#ifdef ARP_PROCESS  if(nh->nh_defaultgate.s_addr!=0 || nh->nh_allarp) {    if(packet->header.proto == htons(ETHERTYPE_ARP)) {      struct arphdr *ahdr;            ahdr = (struct arphdr *)&packet->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 *)(packet->data + /*sizeof(arphdr)*/8 + 1*ETH_ALEN);	tip = (u_int32_t *)(packet->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(packet->header.dest, packet->header.src, ETH_ALEN);	  memcpy(packet->data + 8, nh->nh_defaultether, ETH_ALEN);	  memcpy(packet->header.src, nh->nh_defaultether, ETH_ALEN);	  /* swap ip fields */	  {	    uint32_t tmp;	    tmp=*sip;	    *sip=*tip;	    *tip=tmp;	  }	  if(ns->verbose) {	    fprintf(stderr, "%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;	    fprintf(stderr, "%8s:", nh->nh_name);	    ether_if_print((u_char *)&gndo, &ph, (u_char *)&packet);	  }#endif	}      }    }  }#endif  send_dst(ns, nh, p, packet, len, nh->nh_hub);  }static int match_tap(int port_fd, int data_fd, void *port_data, 		     int port_data_len, void *data){  return(port_fd == data_fd);}void handle_tap_data(struct netjig_state *ns,		     struct nethub       *nh){  struct packet packet;  int len;  len = read(nh->tap_fd, &packet, sizeof(packet));  if(len < 0){    if(errno != EAGAIN) perror("Reading tap data");    return;  }  handle_data(ns, nh, &packet, len, nh->tap_fd, NULL, match_tap);}struct port *alloc_port(struct netjig_state *ns,			struct nethub       *nh){  struct port *port;  port = malloc(sizeof(struct port));  if(port == NULL){    perror("malloc");    return(NULL);  }  memset(port, 0, sizeof(struct port));  TAILQ_INSERT_TAIL(&nh->nh_ports, port, link);  return port;}struct sock_data {  int fd;  struct sockaddr_un sock;};static void send_sock(int fd, void *packet, int len, void *data){  struct sock_data *mine = data;  int err;    err = sendto(mine->fd, packet, len, 0, (struct sockaddr *) &mine->sock,	       sizeof(mine->sock));  if(err != len) perror("send_sock");}static int match_sock(int port_fd, int data_fd, void *port_data, 		      int port_data_len, void *data){  struct sock_data *mine = data;  struct sock_data *port = port_data;  if(port_data_len != sizeof(*mine)) return(0);  return(!memcmp(&port->sock, &mine->sock, sizeof(mine->sock)));}void handle_sock_data(struct netjig_state *ns,		      struct nethub *nh){  struct packet packet;  struct sock_data data;  int len, socklen = sizeof(data.sock);  len = recvfrom(nh->data_fd,		 &packet, sizeof(packet), 0, 		 (struct sockaddr *) &data.sock, &socklen);  if(len < 0){    if(errno != EAGAIN) perror("handle_sock_data");    return;  }  data.fd = nh->data_fd;  handle_data(ns, nh, &packet, len, nh->data_fd, &data, match_sock);}int setup_sock_port(struct netjig_state *ns,		    struct nethub       *nh,		    struct port         *port,		    struct sockaddr_un  *name){  struct sock_data *data;  data = malloc(sizeof(*data));  if(data == NULL){    perror("setup_sock_port");    return(-1);  }  data->fd   = nh->data_fd;  data->sock = *name;    port->sender = send_sock;  port->data   = data;  port->data_len=sizeof(*data);  return(0);}int setup_sock_tap(struct netjig_state *ns,		   struct nethub       *nh,		   int    fd,		   packet_sender        tap_sender){  struct sock_data *data;  struct port *np;  np = alloc_port(ns, nh);  data = malloc(sizeof(*data));  if(data == NULL){    perror("setup_sock_port");    return(-1);  }  data->fd   = nh->data_fd;    np->sender = tap_sender;  np->data   = data;  np->data_len=sizeof(*data);  if(ns->verbose) {    fprintf(stderr, "New tap connection\n");  }  return(0);}void new_port_v0(struct netjig_state *ns,		 struct nethub *nh,		 struct port *p,		 struct request_v0 *req){  switch(req->type){  case REQ_NEW_CONTROL:	  setup_sock_port(ns, nh, p, &req->u.new_control.name);	  break;      default:	  fprintf(stderr, "Bad request type : %d\n", req->type);	  close_descriptor(ns, nh, nh->data_fd);  }}void new_port_v1_v3(struct netjig_state *ns,		    struct nethub *nh,		    struct port   *port,		    enum request_type type, 		    struct sockaddr_un *sock){  int n, err;  switch(type){  case REQ_NEW_CONTROL:    err = setup_sock_port(ns, nh, port, sock);    if(err) return;    n = write(port->control, &nh->data_sun, sizeof(nh->data_sun));    if(n != sizeof(nh->data_sun)){      fprintf(stderr, "Sending data socket name: %s\n", strerror(errno));      close_descriptor(ns, nh, port->control);    }    break;  default:    fprintf(stderr, "Bad request type : %d\n", type);    close_descriptor(ns, nh, port->control);  }}void new_port_v2(struct netjig_state *ns,		 struct nethub       *nh,		 struct port         *p,		 struct request_v2 *req){  fprintf(stderr, "Version 2 is not supported\n");  close_descriptor(ns, nh, p->control);}/* * called when data is ready on a new port */void handle_new_port(struct netjig_state *ns,		     struct nethub *nh,		     struct port   *p) {  union request req;  int len;  len = read(p->control, &req, sizeof(req));  if(len < 0){    if(errno != EAGAIN){      perror("Reading request");      close_descriptor(ns,nh,p->control);    }    return;  }  else if(len == 0){    fprintf(stderr, "EOF from new port\n");    close_descriptor(ns,nh,p->control);    return;  }  if(req.v1.magic == SWITCH_MAGIC) {          if(ns->verbose) {	    fprintf(stderr,		    "switch %s: new connection using daemon v.%d on port %d\n",		    nh->nh_name, req.v2.version, p->control);	  }	  switch(req.v2.version) {	  case 2:		  new_port_v2(ns, nh, p, &req.v2);		  break;		  	  case 3:		  new_port_v1_v3(ns, nh, p, req.v3.type, &req.v3.sock);		  break;		  	  case 1:		  new_port_v1_v3(ns, nh, p, req.v1.type, &req.v1.u.new_control.name);		  break;		  	  default:		  fprintf(stderr, "Request for a version %d port, which this "			  "uml_switch doesn't support\n", req.v2.version);		  break;	  }  } else {	  new_port_v0(ns, nh, p, &req.v0);  }}static void service_port(struct netjig_state *ns,			 struct nethub *nh,			 struct port *port){  int n;  char c;  if(ns->debug > 2) {    fprintf(stderr, "servicing port %d\n", port->control);  }  n = read(port->control, &c, sizeof(c));  if(n < 0) {    fprintf(stderr, "while serving port %d of switch %s reading request: %s",	    port->control, nh->nh_name, strerror(errno));  }  else if(n == 0) {    if(ns->verbose) {      fprintf(stderr, "Disconnect on switch (%s) from %d addr: %02x:%02x:%02x:%02x:%02x:%02x\n",	      nh->nh_name,	      port->control,	      port->most_recent_ethernet[0], port->most_recent_ethernet[1],	      port->most_recent_ethernet[2], port->most_recent_ethernet[3],	      port->most_recent_ethernet[4], port->most_recent_ethernet[5]);    }    remove_fd(ns, port->control);    free_port(ns, nh, port);  }  else {    if(ns->verbose) {      fprintf(stderr,	      "Bad request on switch (%s) from %d addr: %02x:%02x:%02x:%02x:%02x:%02x\n",	      nh->nh_name,	      port->control,	      port->most_recent_ethernet[0], port->most_recent_ethernet[1],	      port->most_recent_ethernet[2], port->most_recent_ethernet[3],	      port->most_recent_ethernet[4], port->most_recent_ethernet[5]);    }  }}void accept_connection(struct netjig_state *ns,		       struct nethub       *nh){  struct sockaddr addr;  struct port *new_port;  int len, new;  len = sizeof(addr);  new = accept(nh->ctl_listen_fd, &addr, &len);  if(new < 0){    perror("accept");    return;  }#if 0  if(fcntl(new, F_SETFL, O_NONBLOCK) < 0){    perror("fcntl - setting O_NONBLOCK");    close(new);    return;  }#endif    new_port = alloc_port(ns, nh);  new_port->control = new;  add_fd(ns, new);}void handle_port(struct netjig_state *ns,		 struct nethub       *nh,		 struct pollfd  *l_fds,		 int             l_nfds,		 int            *l_fd_array,		 int             l_fd_array_size){  struct port *p;  struct port *next_port;    for(p = nh->nh_ports.tqh_first;      p != NULL;      p = next_port)    {      next_port = p->link.tqe_next;      if(p->control < l_fd_array_size &&	 l_fd_array[p->control]!=-1) {	if(l_fds[l_fd_array[p->control]].revents & POLLIN) {	  if(p->sender) {	    service_port(ns, nh, p);	  } else {	    handle_new_port(ns, nh, p);	  }	} else if(l_fds[l_fd_array[p->control]].revents & (POLLHUP|POLLERR)) {	  remove_fd(ns, p->control);	  free_port(ns, nh, p);	}      }    }}  

⌨️ 快捷键说明

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