?? stfl.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 + -