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

📄 stfl.c

📁 实现了ipv6到ipv4的转换(部分实现)
💻 C
字号:
/* * Six To Four Layer * * Copyright 2005 Christopher Read *  * Licensed under the Apache License, Version 2.0 (the "License");  * you may not use this file except in compliance with the License.  * You may obtain a copy of the License at  *  * 		http://www.apache.org/licenses/LICENSE-2.0  *  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License. *  * Author: Chris Read (chris.read@gmail.com) * File: stfl.c *  */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <errno.h>#include <signal.h>#include <syslog.h>#include <pwd.h>#include <fcntl.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/stat.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <pthread.h>#define BUFFER_SIZE 2048// Struct to pass sockets to bridge threadstruct bridge_args {	int sock1;	int sock2;};// Take 2 sockets, feed data from one to the other until one diesvoid bridge(struct bridge_args *args){ 	fd_set rfds; 	struct timeval tv; 	int retval; 	int n = 0; 	char buffer[BUFFER_SIZE]; 	int bufl; 	int sock1; 	int sock2; 	sock1 = args->sock1; 	sock2 = args->sock2; 	 	// Free this up! Just a temp memory block for holding sockets so fast spawning connections don't trample each other 	free(args);	if (sock1 > sock2)		n = sock1 + 1;	else		n = sock2 + 1; 		while (1)	{	 	FD_ZERO(&rfds);	 	FD_SET(sock1, &rfds);	 	FD_SET(sock2, &rfds);		tv.tv_sec = 1;	 	tv.tv_usec = 0;	 			retval = select(n, &rfds, NULL, NULL, &tv);				if (retval == -1)		{			printf("bridge:select:%s\n", strerror(errno));			syslog(LOG_CRIT, "bridge:select:%s", strerror(errno));			break;		}		else if (retval)		{			if (FD_ISSET(sock1, &rfds))			{					bufl = recv(sock1, buffer, BUFFER_SIZE, 0);				if (bufl < 1)					break;				send(sock2, buffer, bufl, 0);			}			if (FD_ISSET(sock2, &rfds))			{					bufl = recv(sock2, buffer, BUFFER_SIZE, 0);				if (bufl < 1)					break;				send(sock1, buffer, bufl, 0);			}		}				}			shutdown(sock1, 2);	shutdown(sock2, 2);		close(sock1);	close(sock2);}// Accept connections on socket srv, when new connection comes in, create new connection to target// and pass the 2 sockets to bridge in a forkvoid monitor(const int srv, const int srv_type, const int tgt_type, const struct sockaddr *target, socklen_t target_len){    struct sockaddr *in_addr;    struct sockaddr_in *addr4;    struct sockaddr_in6 *addr6;    socklen_t in_addr_len, base_addr_len;    in_port_t cport, sport;    int in_sock, out_sock;    pthread_t *thread;	pthread_attr_t thread_attr;    struct bridge_args *args;    char caddr[INET6_ADDRSTRLEN + 1];    char saddr[INET6_ADDRSTRLEN + 1];	pthread_attr_init(&thread_attr);		// Need to do some nasty hacks around IPv6/IPv4 structs. Would be nice if inet_ntop too a sockaddr instead...	if (srv_type == AF_INET)		base_addr_len = sizeof(struct sockaddr_in);	else		base_addr_len = sizeof(struct sockaddr_in6);			in_addr = malloc(base_addr_len);	if (tgt_type == AF_INET)	{		addr4 = (struct sockaddr_in *)target;		inet_ntop(tgt_type, (void *)&addr4->sin_addr, saddr, INET6_ADDRSTRLEN);		sport = ntohs(addr4->sin_port);	}	else	{		addr6 = (struct sockaddr_in6 *)target;		inet_ntop(tgt_type, (void *)&addr6->sin6_addr, saddr, INET6_ADDRSTRLEN);		sport = ntohs(addr6->sin6_port);	}		while (1)	{		// May not need these next two. Just being paranoid to be sure...		in_addr_len = base_addr_len;		memset(in_addr, 0, base_addr_len);	    	in_sock = accept(srv, (struct sockaddr *)in_addr, &in_addr_len);	    	    if (in_sock < 0)	    {	    	syslog(LOG_ERR, "monitor:accept:%s", strerror(errno));		printf("monitor:accept:%s\n", strerror(errno));		exit(-1);	    }	    		    // Grab address details of client we're serving	    if (srv_type == AF_INET)	    {		    addr4 = (struct sockaddr_in *)in_addr;        	inet_ntop(srv_type, (void *)&addr4->sin_addr, caddr, INET6_ADDRSTRLEN);        	cport = ntohs(addr4->sin_port);	    }        else        {		    addr6 = (struct sockaddr_in6 *)in_addr;        	inet_ntop(srv_type, (void *)&addr6->sin6_addr, caddr, INET6_ADDRSTRLEN);        	cport = ntohs(addr6->sin6_port);        }    		out_sock = socket(tgt_type, SOCK_STREAM, 0);		    if (connect(out_sock, target, target_len) != 0)	    {	    	printf("monitor:connect:%s connecting to %s:%u\n", strerror(errno), saddr, sport);	    	syslog(LOG_ERR, "monitor:connect:%s connecting to %s:%u", strerror(errno), saddr, sport);	    	shutdown(in_sock, 2);	    	close(in_sock);	    }	    else	    {		    printf("Connecting %s:%u to %s:%u\n", caddr, cport, saddr, sport);		    syslog(LOG_NOTICE, "Connecting %s:%u to %s:%u", caddr, cport, saddr, sport);				// Need a temp struct to pass sockets over to thread on. Freed up early in the bridge...	    			args = malloc(sizeof(struct bridge_args));			args->sock1 = in_sock;			args->sock2 = out_sock;						thread = malloc(sizeof(pthread_t));			// Fire and forget the thread...			pthread_create(thread, &thread_attr, (void *)bridge, args);			free(thread);	    }	}		pthread_attr_destroy(&thread_attr);	free(in_addr);}// The main event. Params are passed on the command line.int main(int argc, char *argv[]){	int srv;	int error;	int opt;	char *bind_ip = "";	char *bind_port = "";	char *target_ip = "";	char *target_port = "";	char *user = "";	uid_t uid;	struct passwd *pwinfo;	int foreground = 0;	int f;	struct addrinfo hints, *srv_info, *tgt_info;		printf("Six To Four Layer\n");		if (argc < 5)	{		printf("Usage: %s -l <listen ip> -p <listen port> -t <target ip> -d <target port> [-u <uid>] [-f]\n", argv[0]);		printf("\t-u: User ID to run as once bound to listening port. Can be name or number\n");		printf("\t-f: Run in the foreground. Usefull if you want to test or debug\n");		return 0;	}		while ((opt = getopt(argc, argv, "l:p:t:d:u:f")) != EOF)	{		switch (opt)		{			case 'l':				bind_ip = optarg;				break;			case 'p':				bind_port = optarg;				break;			case 't':				target_ip = optarg;				break;			case 'd':				target_port = optarg;				break;			case 'u':				user = optarg;				break;			case 'f':				foreground = 1;				break;		}	}		if ((bind_ip == "") || (bind_port == "") || (target_ip == "") || (target_port == ""))	{		printf("Missing parameters!\n");		exit(-1);	}	if (strlen(user) > 20)	{		printf("UID is too long. Must be unix name or uid.\n");		exit(-1);	}	if (foreground == 0)	{		f = fork();		if (f < 0) 			exit(1); 		if (f > 0) 			exit(0); /* parent exits */		/* child (daemon) continues */		setsid(); /* obtain a new process group */		for (f = getdtablesize(); f >= 0; --f) 			close(f); /* close all descriptors */		f = open("/dev/null", O_RDWR); 		dup(f); 		dup(f); /* handle standard I/O because we just closed all descriptors */	}		openlog("stfl", LOG_PID, LOG_DAEMON);			printf("Bridging connections on [%s]:%s to [%s]:%s\n", bind_ip, bind_port, target_ip, target_port);	syslog(LOG_NOTICE, "Bridging connections on [%s]:%s to [%s]:%s\n", bind_ip, bind_port, target_ip, target_port);		memset(&hints, 0, sizeof(hints));	hints.ai_family = PF_UNSPEC;	hints.ai_socktype = SOCK_STREAM;		// Get server socket info	error = getaddrinfo(bind_ip, bind_port, &hints, &srv_info);	if (error)	{		syslog(LOG_CRIT, "%s", gai_strerror(error));		printf("%s\n", gai_strerror(error));		exit(-1);	}		// Get target socket info	error = getaddrinfo(target_ip, target_port, &hints, &tgt_info);	if (error)	{		syslog(LOG_CRIT, "%s", gai_strerror(error));		printf("%s\n", gai_strerror(error));		exit(-1);	}		srv = socket(srv_info->ai_family, srv_info->ai_socktype, srv_info->ai_protocol);	if (srv < 0)	{		syslog(LOG_CRIT, "main:socket:%s", strerror(errno));		printf("main:socket:%s\n", strerror(errno));		exit(-1);	}			bind(srv, srv_info->ai_addr, srv_info->ai_addrlen);	if (error < 0)	{		syslog(LOG_CRIT, "main:bind:%s", strerror(errno));		printf("main:bind:%s\n", strerror(errno));		exit(-1);	}			// Check if we need to give up root now...	if (strcmp(user, "") != 0)	{		if (getuid() != 0)		{			syslog(LOG_ERR, "main:uid:%s", "Cannot change user when not root, continuing as current user");			printf("main:uid:%s\n", "Cannot change user when not root, continuing as current user");		}		else		{			uid = strtol(user, (char **)NULL, 10);			if ((uid == LONG_MIN) || (uid == LONG_MAX) || (uid == 0))			{				pwinfo = getpwnam(user);				if (pwinfo == NULL)				{					syslog(LOG_CRIT, "main:uid:%s is not a valid user on this system", user);					printf("main:uid:%s is not a valid user on this system\n", user);					exit(-1);				}				uid = pwinfo->pw_uid;			}						if (setuid(uid) != 0)			{				syslog(LOG_CRIT, "main:uid:Unable to change to uid %s", user);				printf("main:uid:Unable to change to uid %s\n", user);				exit(-1);			}			printf("Switched to user %s\n", user);		}	}		listen(srv, 5);	monitor(srv, srv_info->ai_family, tgt_info->ai_family, tgt_info->ai_addr, tgt_info->ai_addrlen);		printf("Shutting down...\n");	syslog(LOG_NOTICE, "Shutting down...\n");		close(srv);		freeaddrinfo(srv_info);	freeaddrinfo(tgt_info); 	 	return 0;	}

⌨️ 快捷键说明

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