예제 #1
0
파일: dns.c 프로젝트: AmesianX/WinQEMU
/**
 * DNS: Sends a standard DNS-query (read request package) to a DNS-server.
 *      DNS-server respones with host IP or signals some error condition.
 *      Responses from the server are handled by handle_dns function.
 *
 * @param  fd          socket descriptor
 * @param  domain_name the domain name given as series of labels preceded
 *                     with length(label) and terminated with 0  
 *                     <br>(e.g. "\3,w,w,w,\4,h,o,s,t,\3,o,r,g,\0")
 * @see                handle_dns
 */
static void
dns_send_query(int fd, int8_t * domain_name, uint8_t ip_version)
{
	int qry_len = strlen((char *) domain_name) + 5;
	int iphdr_len = (ip_version == 4) ? sizeof(struct iphdr) : sizeof(struct ip6hdr);
	ip6_addr_t server_ipv6;

	uint32_t packetsize = iphdr_len +
	                      sizeof(struct udphdr) + sizeof(struct dnshdr) +
	                      qry_len;

	memset(ether_packet, 0, packetsize);
	fill_dnshdr(&ether_packet[
	            iphdr_len + sizeof(struct udphdr)],
	            domain_name,
		    ip_version);
	fill_udphdr(&ether_packet[iphdr_len],
		    sizeof(struct dnshdr) +
		    sizeof(struct udphdr) + qry_len,
	            UDPPORT_DNSC, UDPPORT_DNSS);
	if (ip_version == 4) {
		fill_iphdr(ether_packet,
			   sizeof(struct dnshdr) + sizeof(struct udphdr) +
			   iphdr_len + qry_len,
			   IPTYPE_UDP, 0, dns_server_ip);
	} else {
		memcpy(server_ipv6.addr, dns_server_ipv6, 16);
		fill_ip6hdr(ether_packet,
			    sizeof(struct dnshdr) + sizeof(struct udphdr) + qry_len,
			    IPTYPE_UDP, get_ipv6_address(),
			    &server_ipv6);
	}

	send_ip(fd, ether_packet, packetsize);
}
	std::set<boost::asio::ip::address> getlist()
	{
		std::set<boost::asio::ip::address> result;

		struct nlmsg_list *linfo = NULL;
		struct nlmsg_list *ainfo = NULL;
		struct rtnl_handle rth;

		if (rtnl_open(&rth, 0) < 0) {
			std::cout << "rtnl_open failed\n";
			return result;
		}

		if (rtnl_wilddump_request(&rth, AF_INET6, RTM_GETLINK) < 0) {
			std::cout << "cannot send dump request\n";
			rtnl_close(&rth);
			return result;
		}

		if (rtnl_dump_filter(&rth, &store_nlmsg, &linfo, NULL, NULL) < 0) {
			std::cout << "dump terminated\n";
			rtnl_close(&rth);
			return result;
		}

		if (rtnl_wilddump_request(&rth, AF_INET6, RTM_GETADDR) < 0) {
			std::cout << "cannot send dump request\n";
			rtnl_close(&rth);
			return result;
		}

		if (rtnl_dump_filter(&rth, &store_nlmsg, &ainfo, NULL, NULL) < 0) {
			std::cout << "dump terminated\n";
			rtnl_close(&rth);
			return result;
		}

		{
			struct nlmsg_list **lp;
			lp=&linfo;
			nlmsg_list* l;
			while ((l=*lp)!=NULL) {
				int ok = 0;
				struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(&l->h);
				struct nlmsg_list *a;

				for (a=ainfo; a; a=a->next) {
					struct nlmsghdr *n = &a->h;
					struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA(n);

					/* NOTE: ifi_index and ifa_index should have the same type (int), but for
					 * some reason they are not... So instead of a normal (in)equality comparison
					 * we do a bit-wise compare.
					 */
					if (ifi->ifi_index ^ ifa->ifa_index)
						continue;
					if (ifa->ifa_family != AF_INET6)
						continue;

					ok = 1;
					break;
				}
				if (!ok)
					*lp = l->next;
				else
					lp = &l->next;
			}
		}

		for (nlmsg_list* l=linfo; l; l = l->next) {
			for (nlmsg_list* a=ainfo; a; a = a->next) {
				boost::asio::ip::address_v6 addr = get_ipv6_address(&l->h, &a->h);
				if (!addr.is_unspecified() && !addr.is_loopback())
					result.insert(addr);
			}
		}

		rtnl_close(&rth);

		for (nlmsg_list* l=linfo; l; ) {
			nlmsg_list* o = l;
			l = l->next;
			free(o);
		}

		for (nlmsg_list* a=ainfo; a; ) {
			nlmsg_list* o = a;
			a = a->next;
			free(o);
		}

		return result;
	}
void *Reflector(void *threadarg)
{
	int ioctl_s;
	struct thread_data *my_data;
	my_data = (struct thread_data *)threadarg;
	struct in_addr multicastaddress_in; //IPv4 multicast address from command line 
	struct in_addr multicastaddress_out; 
	struct sockaddr_in6 tmp_saddr6;
	struct ifreq ifr;
	struct ipaddr_str buf; 
	int mcdataport4; //IPv4 multicast port 1
	int mcdataport;  //IPv4 multicast port 2  

/*define variables*/

	int mcdatarecvfd4;   //multicast data receive socket side 1
	int mcdatarecvfd;    //multicast data receive socket side 2


	int sendfd4;   //local send socket IPv4 side 1
	int sendfd;    //local send socket IPv4 side 2

	int ttl1;   //time to live IPv4 side 1
	int ttl2;       //time to live IPv4 side 2
	struct sockaddr_in mcdataaddr4; //reception IPv4 sockaddr  
	struct sockaddr_in mcdataaddr; //reception IPv44 sockaddr


	char myhostnameipaddress4[20];   // IPv4 reflector's address string
	char myhostnameipaddress[20];    // IPv44 reflector's address string
	char addressstring4[20];         // IPv4 address string
	char addressstring[20];          // IPv44 address string

	struct sockaddr_in localsendaddr4; //IPv4 address of outgoing packets interface 1
	struct sockaddr_in localsendaddr; //IPv4 address of outgoing packets interface 2

	struct sockaddr_in sourceaddr4; //IPv4 address of incoming packets interface 1
	struct sockaddr_in sourceaddr; //IPv4 address of incoming packets interface 2

	struct ip_mreq mcdatareq4; //IPv4 join group structure
	struct ip_mreq mcdatareq; //IPv44 join group structure


	int mcdataaddrlen;  //IPv4 multicast address length
	unsigned int sourceaddrlen;  //IPv4 source address length

	char mcdatarecvbuf4[MSGBUF_SIZE]; //IPv4 multicast receive buffer
	char mcdatarecvbuf[MSGBUF_SIZE];  //IPv44 multicast receive buffer



	fd_set readfds; // file descriptors set 
	int maxfds;     // max number of file descriptors
	int nfds;      
	int nr;  // number of bytes read with recvfrom
	int ns;  // number of bytes sent with sendto
	int chksrc;  // asserts if source address is not the reflector's one
	int debugon=1;
	int n2;
	char inputbuf[32];

/* IPv4 multicast address */
	if((inet_pton(AF_INET,my_data->multicast_addr1,&multicastaddress_in.s_addr))!=1){
		printf("bad multicast IPv4 address format\n");
		exit (1);
	} 
	//printf("multicastaddress side 1 v4 =%s\n",my_data->multicast_addr1);
/* IPv4 multicast address */
	if((inet_pton(AF_INET,my_data->multicast_addr2,&multicastaddress_out.s_addr))!=1){
		printf("bad multicast IPv4 address format\n");
		exit (1);
	}
	//printf("multicastaddress side 2 v4 =%s\n",my_data->multicast_addr2);


/* IPv4 multicast ports */
	
		mcdataport4 = my_data->port1;	
		mcdataport = my_data->port2;
	
	
/* Time to live for IPv4 multicast */
	ttl1 = my_data->ttl1;

/* Time to live for IPv4 multicast */
	ttl2 = my_data->ttl2;

	IP_VERSION=4;
	if (IP_VERSION==4 )//
	{
		ioctl_s = socket(AF_INET, SOCK_DGRAM, 0);
		if (ioctl_s < 0) 
		{	
			syslog(LOG_ERR, "ioctl socket: %m");
			exit (0);
		}
		/* INTERFACE 1 */
		memset(&ifr, 0, sizeof(struct ifreq));
		strncpy(ifr.ifr_name, my_data->interface1, IFNAMSIZE);       
	/* Check interface address (IPv4)  */	  
		if(ioctl(ioctl_s, SIOCGIFADDR, &ifr) < 0) 
		{
			printf( "\tCould not get address of interface 1 - removing it\n");
			exit(0);
		}
		sockaddr4_to_string(&myhostnameipaddress4, &ifr.ifr_addr);

	/* INTERFACE 2 */
		memset(&ifr, 0, sizeof(struct ifreq));
		strncpy(ifr.ifr_name, my_data->interface2, IFNAMSIZE); 
				/* Check interface address (IPv4)  */	  
		if(ioctl(ioctl_s, SIOCGIFADDR, &ifr) < 0) 
		{
			printf( "\tCould not get address of interface 2 - removing it\n");
			exit(0);
		}

		sockaddr4_to_string(&myhostnameipaddress, &ifr.ifr_addr);
	}
	else
	{
	/* Global address mode */
		int ipv6_addrtype = 0; /* global */
	/* Get  IPV6 GLOBAL interface address  */ 
		memset(&ifr, 0, sizeof(struct ifreq));
		strncpy(ifr.ifr_name, my_data->interface2, IFNAMSIZE);  
		if(get_ipv6_address(ifr.ifr_name, &tmp_saddr6, ipv6_addrtype ) <= 0)
		{
			printf( "\tCould not find site-local IPv6 address for %s\n", ifr.ifr_name);
		}

		memset(&ifr, 0, sizeof(struct ifreq));
		strncpy(ifr.ifr_name, my_data->interface2, IFNAMSIZE); 
//	printf("\n Adding interface : %s \n", my_data->interface2);   
	/* Get  IPV6 GLOBAL interface address  */  
		if(get_ipv6_address(ifr.ifr_name, &tmp_saddr6, ipv6_addrtype ) <= 0)
		{
			printf( "\tCould not find site-local IPv6 address for %s\n", ifr.ifr_name);
		}
	} 
/* Structures initialization */

/*enter the address/port data into the mcdataaddr structure for IPv4*/
	bzero((char *) &mcdataaddr4, sizeof(mcdataaddr4));
	mcdataaddr4.sin_family=AF_INET;
	mcdataaddr4.sin_addr.s_addr = multicastaddress_in.s_addr;
	mcdataaddr4.sin_port = htons(mcdataport4);

/*enter the address/port data into the mcdataaddr structure for IPv4*/
	bzero((char *) &mcdataaddr, sizeof(mcdataaddr));
	mcdataaddr.sin_family=AF_INET;
	mcdataaddr.sin_addr.s_addr = multicastaddress_out.s_addr;
	mcdataaddr.sin_port = htons(mcdataport);

	
/*enter the address/port data into the localsendaddr structure for IPv4*/
	bzero((char *) &localsendaddr4, sizeof(localsendaddr4));
	localsendaddr4.sin_family=AF_INET;
	inet_pton(AF_INET, myhostnameipaddress4 , &localsendaddr4.sin_addr.s_addr);
	localsendaddr4.sin_port = htons(0);
//LL
//	inet_ntop(AF_INET, &localsendaddr4.sin_addr.s_addr,addressstring ,sizeof(addressstring));
//	printf("threaded function local sender addr side 1=%s \t",addressstring);

/*enter the address/port data into the localsendaddr structure for IPv4*/ 
	bzero((char *) &localsendaddr, sizeof(localsendaddr));
	localsendaddr.sin_family=AF_INET;
	inet_pton(AF_INET, myhostnameipaddress , &localsendaddr.sin_addr.s_addr);
	localsendaddr.sin_port = htons(0);
//LL
//	inet_ntop(AF_INET, &localsendaddr.sin_addr.s_addr,addressstring ,sizeof(addressstring));
//	printf("threaded function local sender addr side 2=%s\n", addressstring);

/*enter the address/port data into the mcdatareq structure for IPv4*/
	bzero((char *) &mcdatareq4, sizeof(mcdatareq4));
//	mcdatareq4.imr_interface.s_addr=htonl(INADDR_ANY); < force to add a multicast route
	inet_pton(AF_INET, myhostnameipaddress4 ,&mcdatareq4.imr_interface.s_addr );
	mcdatareq4.imr_multiaddr.s_addr=multicastaddress_in.s_addr;
// inet_pton(AF_INET, myhostnameipaddress4 , &mcdatareq4.imr_interface.s_addr);



/*enter the address/port data into the mcdatareq structure for IPv4*/
	bzero((char *) &mcdatareq, sizeof(mcdatareq));
	inet_pton(AF_INET, myhostnameipaddress ,&mcdatareq.imr_interface.s_addr );
//	mcdatareq.imr_interface.s_addr=htonl(INADDR_ANY);
	mcdatareq.imr_multiaddr.s_addr=multicastaddress_out.s_addr;

/*get the sendfd socket linked to  the first address of the current host */
	if ((sendfd4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		perror("can't open sendfd socket!");
		exit (1);
	}

	if (bind(sendfd4, (struct sockaddr *) &localsendaddr4, \
	sizeof(localsendaddr4)) < 0) {

		perror("can't bind localsendaddr v4 to socket!");
		exit(1);
	}
/*get the sendfd socket linked to  the first address of the current host*/
	if ((sendfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		perror("can't open sendfd socket!");
		exit (1);
	}

	if (bind(sendfd, (struct sockaddr *) &localsendaddr, \
	sizeof(localsendaddr)) < 0) {
		perror("can't bind localsendaddr v4 side 2 to socket!");
		exit(1);
	} 

	if ((mcdatarecvfd4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		perror("can't open mcdatarecvfd4 socket!");
		exit(1);
	}

/*allow multiple processes per host to read from IPv4 sockets side 2*/
	if (setsockopt(mcdatarecvfd4, SOL_SOCKET, SO_REUSEADDR, &mcdataaddr4, sizeof(mcdataaddr4)) < 0) {
		perror("SO_REUSEADDR setsockopt v4\n");
	}  

	if (bind(mcdatarecvfd4, (struct sockaddr *) &mcdataaddr4, \
	sizeof(mcdataaddr4)) < 0) {
		inet_ntop(AF_INET, &mcdataaddr4.sin_addr.s_addr,addressstring ,sizeof(addressstring));
		printf("with address of bind %s\n", addressstring);
		perror("can't bind mcdataaddr v4 to socket!");
		exit(1);
	}


	if (multicastaddress_out.s_addr!=multicastaddress_in.s_addr)
	{
	//multicast data receive socket side 2 
	/*get a mcdatarecvfd socket, bind to address for IPv4*/
		if ((mcdatarecvfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
			perror("can't open mcdatarecvfd4 socket!");
			exit(1);
		}
		/*allow multiple processes per host to read from IPv4 sockets side 2*/
		if (setsockopt(mcdatarecvfd, SOL_SOCKET, SO_REUSEADDR, &mcdataaddr, sizeof(mcdataaddr)) < 0) {
			perror("SO_REUSEADDR setsockopt v4\n");
		}  

		if (bind(mcdatarecvfd, (struct sockaddr *) &mcdataaddr, \
		sizeof(mcdataaddr)) < 0) {
			perror("can't bind mcdataaddr v4 side 2 to socket!");
			exit(1);
		}

	}
	else 
	{
		mcdatarecvfd= mcdatarecvfd4;
	}

/*set socket options to join multicast group in IPv4*/
	if (setsockopt(mcdatarecvfd4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcdatareq4,\
	sizeof(mcdatareq4)) < 0) {
		perror("can't set socket options to join multicast group data v4 side 1!");
		exit(1);
	} 


/*set socket options to join multicast group in IPv4*/
	if (setsockopt(mcdatarecvfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcdatareq,\
	sizeof(mcdatareq)) < 0) {
		perror("can't set socket options to join multicast group data v4 side 2!");
		exit(1);
	} 

/*now set multicast socket TTL option for IPv4*/
	if (setsockopt(sendfd4, IPPROTO_IP, IP_MULTICAST_TTL, \
		&ttl1, sizeof(ttl1)) < 0)
		perror("can't set multicast ttl v4 socket option!");

/*now set multicast socket TTL option for IPv4*/
	if (setsockopt(sendfd, IPPROTO_IP, IP_MULTICAST_TTL, \
		&ttl2, sizeof(ttl2)) < 0)
		perror("can't set multicast ttl v4 socket option!");


/*define the sizes of the address structures*/
	mcdataaddrlen=sizeof(mcdataaddr4);
	sourceaddrlen=sizeof(sourceaddr4);
	
/*start infinite while loop*/
/*and check for activity on sockets*/

/*set up the select sytem call parameters*/  
/*zero out the readfds and writefds lists, then add*/
/*the file descriptors of interest*/
	while(1) { 
		
    FD_ZERO(&readfds);
    FD_SET(mcdatarecvfd4, &readfds);
    FD_SET(mcdatarecvfd, &readfds);
    
    if (debugon >= 1) {
      FD_SET(0, &readfds);
    }
    
    maxfds = mcdatarecvfd4 + 5;
    /*check for activity*/
    nfds = select(maxfds, &readfds, NULL, NULL, NULL);
  
    /*if specified on the command line, check for input on stdin*/
    if (debugon >= 1) {
      if (FD_ISSET(0, &readfds)) {
	n2 = read(0,inputbuf, sizeof(inputbuf));
	inputbuf[n2>0? n2-1: 0] = '\0';
 	if (!strcmp(inputbuf,"q")) {
	  programshutdown();
	} 
      }
      fflush(stdout); 
    }
    

	/*1:receive from IPv4, send on IPv44  - data*/ 
		if (FD_ISSET(mcdatarecvfd4, &readfds)) {
			nr = recvfrom(mcdatarecvfd4, mcdatarecvbuf4, MSGBUF_SIZE, 0, (struct sockaddr *) \
				&sourceaddr4, &sourceaddrlen);
			if (debugon >= 2){ 
				inet_ntop(AF_INET, &sourceaddr4.sin_addr.s_addr, addressstring4 , sizeof(addressstring4));
				printf("\nreading from mcdatarecvfd4, got data from %s\n", addressstring4);
			}

			if (sourceaddr4.sin_addr.s_addr == localsendaddr4.sin_addr.s_addr){
				chksrc = 0;
				if (debugon >= 2) 
					printf("don't retransmit multicastv4 sourced from gateway machine\n");
			} else {
				chksrc = 1;
				if (debugon >= 2) 
					printf("retransmit to multicast address\n");
			}

			if (chksrc) {
				if (nr < 0)
					printf ("mcdatarecvfd4:recvfrom over multicast v4 address error!(1)\n");     

	/*now send to IPv4*/
				if (multicastaddress_out.s_addr != INADDR_ANY) {
					if (debugon >= 2) {
						inet_ntop(AF_INET, &mcdataaddr.sin_addr.s_addr,addressstring4 ,sizeof(addressstring4));
						printf("sending to %s\n", addressstring4);
					} 

					ns = sendto(sendfd, mcdatarecvbuf4, nr, 0, (struct sockaddr *)&mcdataaddr, \
						sizeof(mcdataaddr));
				} else {
					if (debugon >= 2) printf("not resending to ORIGINATOR! or array entry = 0\n");
				}
			}
		}



	/*2:receive from IPv4 side 2, send on IPv44 side 1  - data*/ 
		if (FD_ISSET(mcdatarecvfd, &readfds)) {
			nr = recvfrom(mcdatarecvfd, mcdatarecvbuf, MSGBUF_SIZE, 0, (struct sockaddr *) \
				&sourceaddr, &sourceaddrlen);
			if (debugon >= 2){ 
				inet_ntop(AF_INET, &sourceaddr.sin_addr.s_addr, addressstring , sizeof(addressstring));
				printf("\nreading from mcdatarecvfd side 2, got data from %s\n", addressstring);
			}

			if (sourceaddr.sin_addr.s_addr == localsendaddr.sin_addr.s_addr){
				chksrc = 0;
				if (debugon >= 2) 
					printf("don't retransmit multicastv4 sourced from gateway machine\n");
			} else {
				chksrc = 1;
				if (debugon >= 2) 
					printf("retransmit to multicast address side 1\n");
			}

			if (chksrc) {
				if (nr < 0)
					printf ("mcdatarecvfd:recvfrom over multicast v4 address error!(1)\n");     

	/*now send to IPv4*/
				if (multicastaddress_in.s_addr != INADDR_ANY) {
					if (debugon >= 2) {
						inet_ntop(AF_INET, &mcdataaddr4.sin_addr.s_addr,addressstring ,sizeof(addressstring));
						printf("sending to %s\n", addressstring);
					} 	  
					ns = sendto(sendfd4, mcdatarecvbuf, nr, 0, (struct sockaddr *)&mcdataaddr4, \
						sizeof(mcdataaddr4));
				} else {
					if (debugon >= 2) printf("not resending to ORIGINATOR! or array entry = 0\n");
				}
			}
		}
	} //end of while loop

}