-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmyserver.c
More file actions
609 lines (285 loc) · 9.12 KB
/
myserver.c
File metadata and controls
609 lines (285 loc) · 9.12 KB
1
// 客户端VPN 服务器#include <arpa/inet.h>#include <openssl/ssl.h>#include <openssl/err.h>#include <netdb.h>#include <unistd.h>#include <fcntl.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <arpa/inet.h>#include <linux/if.h>#include <linux/if_tun.h>#include <sys/ioctl.h>#include <shadow.h>#include <crypt.h>#define CHK_SSL(err) if ((err) < 1) { ERR_print_errors_fp(stderr); exit(2); }#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); }#define PORT_NUMBER 55555#define BUFF_SIZE 2000#define MAX_CONNECTION 10#define NIPQUAD_FMT "%u.%u.%u.%u"#define NIPQUAD(addr) \ ((unsigned char *)&addr)[0], \ ((unsigned char *)&addr)[1], \ ((unsigned char *)&addr)[2], \ ((unsigned char *)&addr)[3]typedef struct info{ int used;// if not used ,set to be -1, else set to be unsigned int ip_addr; pid_t pid;int writefd; int readfd; // 添加管道文件描述符?} Info;typedef struct _ip_header{ unsigned char ver_ihl; // 版本 (4 bits) + 首部长度 (4 bits) unsigned char tos; // 服务类型(Type of service) unsigned short tlen; // 总长(Total length) unsigned short identification; // 标识(Identification) unsigned short flags_fo; // 标志位(Flags) (3 bits) + 段偏移量(Fragment offset) (13 bits) unsigned char ttl; // 存活时间(Time to live) unsigned char proto; // 协议(Protocol) unsigned short crc; // 首部校验和(Header checksum) unsigned char saddr[4]; // 源地址(Source address) unsigned char daddr[4]; // 目标地址(Destination address)// 16 - 19 length equals 4}ip_header;int pipeArray1[MAX_CONNECTION][2];int pipeArray2[MAX_CONNECTION][2];Info infoArray[MAX_CONNECTION];int curConnNum = 0;int setupTCPServer(); // Defined in Listing 19.10int loginCheck(char * user, char* passwd);void processRequest(SSL* ssl, int sock); // Defined in Listing 19.12//创建tun设备int createTunDevice() { int tunfd; struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TUN | IFF_NO_PI; tunfd = open("/dev/net/tun", O_RDWR); ioctl(tunfd, TUNSETIFF, &ifr); return tunfd;}//初始化TCP,返回监听套接字描述符int setupTCPServer(){ struct sockaddr_in sa_server; int listen_sock; listen_sock= socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); CHK_ERR(listen_sock, "socket"); memset (&sa_server, '\0', sizeof(sa_server)); sa_server.sin_family = AF_INET; sa_server.sin_addr.s_addr = INADDR_ANY; sa_server.sin_port = htons (4433); int err = bind(listen_sock, (struct sockaddr*)&sa_server, sizeof(sa_server)); CHK_ERR(err, "bind"); err = listen(listen_sock, 5); CHK_ERR(err, "listen"); return listen_sock;}//有数据包从内网发送到外网void tunSelected(int tunfd, SSL * ssl){ int len; char buff[BUFF_SIZE]; printf("Got a packet from TUN\n"); bzero(buff, BUFF_SIZE); len = read(tunfd, buff, BUFF_SIZE); SSL_write(ssl, buff, len);}//有数据包从外网发送到内网,从SSL 读取数据,写到tun0设备void socketSelected (int tunfd, SSL* ssl){ int len; char buff[BUFF_SIZE]; printf("Got a packet from the tunnel\n"); bzero(buff, BUFF_SIZE); len = SSL_read(ssl, buff, BUFF_SIZE); write(tunfd, buff, len);}SSL* iniSSL(){ SSL_METHOD *meth; SSL_CTX* ctx; SSL *ssl; int err; // Step 0: OpenSSL library initialization // This step is no longer needed as of version 1.1.0. SSL_library_init(); SSL_load_error_strings(); SSLeay_add_ssl_algorithms(); // Step 1: SSL context initialization meth = (SSL_METHOD *)TLSv1_2_method(); ctx = SSL_CTX_new(meth); SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); // Step 2: Set up the server certificate and private key SSL_CTX_use_certificate_file(ctx, "./cert_server/server-cert.pem", SSL_FILETYPE_PEM); SSL_CTX_use_PrivateKey_file(ctx, "./cert_server/server-key.pem", SSL_FILETYPE_PEM); // Step 3: Create a new SSL structure for a connection ssl = SSL_new (ctx); return ssl;}int main(int argc, char const *argv[]){ int tunfd; SSL * ssl; int listenSock; tunfd = createTunDevice(); ssl = iniSSL(); listenSock = setupTCPServer(); struct sockaddr_in sa_client; size_t client_len = sizeof(struct sockaddr_in); /*int sock = accept(listenSock, (struct sockaddr*)&sa_client, &client_len); SSL_set_fd(ssl,sock); int err = SSL_accept (ssl); CHK_SSL(err); // loginrequest printf ("SSL connection established!\n");*/ while (1) { fd_set readFDSet; FD_ZERO(&readFDSet); FD_SET(listenSock, &readFDSet); FD_SET(tunfd, &readFDSet); for(int i = 0; i < curConnNum; ++i) { if(infoArray[i].ip_addr == 0) { FD_SET(infoArray[i].readfd,&readFDSet); } } select(FD_SETSIZE, &readFDSet, NULL, NULL, NULL); for(int i = 0; i < curConnNum ; ++i) { if(FD_ISSET(infoArray[i].readfd,&readFDSet)) { unsigned int ip_addr; read(infoArray[i].readfd,&ip_addr,sizeof(ip_addr)); infoArray[i].ip_addr = ip_addr ; } } if (FD_ISSET(tunfd, &readFDSet)) { //获取数据包的目的IP地址,搜索infoArray中的内容,如果没有匹配就丢弃。 int len; char buff[BUFF_SIZE]; printf("Got a packet from TUN\n"); bzero(buff,BUFF_SIZE); len = read(tunfd,buff,BUFF_SIZE); ip_header * src = buff; src->daddr; unsigned int targetIp = *(unsigned int *)(buff + 16); // 专门的函数用来输出 printf("ip = " NIPQUAD_FMT "\n", NIPQUAD(targetIp)); for(int i = 0; i < curConnNum; ++i){ if(targetIp == infoArray[i].ip_addr) { printf("Found %d\n",i); write(infoArray[i].writefd,buff,len); } } } //新建进程 if (FD_ISSET(listenSock, &readFDSet)) { printf("监听到连接请求,新建进程\n"); int sock = accept(listenSock,(struct sockaddr*)&sa_client, &client_len); //infoArray[curConnNum].ip_addr = ntohl(sa_client.sin_addr.s_addr); printf("sa_client %d\n",sa_client.sin_addr.s_addr); pipe(pipeArray1[curConnNum]); pipe(pipeArray2[curConnNum]); infoArray[curConnNum].writefd = pipeArray1[curConnNum][1]; infoArray[curConnNum].readfd = pipeArray2[curConnNum][0]; infoArray[curConnNum].ip_addr = 0; pid_t childPid = fork(); if(childPid ==0) { close (listenSock); SSL_set_fd (ssl, sock); int err = SSL_accept (ssl); CHK_SSL(err); // login check module char userNameBuf[20] = ""; char passwdBuf[100] = ""; int len = SSL_read(ssl,userNameBuf,sizeof(userNameBuf) -1); userNameBuf[len] = '\0'; printf("received userName %s\n",userNameBuf); len = SSL_read(ssl,passwdBuf,sizeof(passwdBuf)-1); passwdBuf[len] = '\0'; printf("receive passwd %s\n",passwdBuf); if(loginCheck(userNameBuf,passwdBuf) == -1) { printf("Oops,can't pass the login Check\n"); close(sock); return 0; } printf ("SSL connection established!\n"); int flag = 0; while(1) { //如果可读,将其写入到tun文件描述符取 close(pipeArray1[curConnNum][1]); close(pipeArray2[curConnNum][0]); fd_set readFDSet; FD_ZERO(&readFDSet); FD_SET(sock, &readFDSet); //这里需要添加的是与主进程的管道文件描述符 FD_SET(pipeArray1[curConnNum][0], &readFDSet); select(FD_SETSIZE, &readFDSet, NULL, NULL, NULL); if (FD_ISSET(pipeArray1[curConnNum][0], &readFDSet)) { //从管道读取,ssl write 管道 int len; char buff[BUFF_SIZE]; printf("Got a packet from PIPE\n"); bzero(buff, BUFF_SIZE); len = read(pipeArray1[curConnNum][0], buff, BUFF_SIZE); SSL_write(ssl, buff, len); } if (FD_ISSET(sock, &readFDSet)) { //ssl read write to tunfd // 根据IP数据报的源IP地址,通过管道写,向主进程发送 // 该连接对应的管道IP地址 printf("Got a packet from the tunnel\n"); int len; char buff[BUFF_SIZE]; bzero(buff, BUFF_SIZE); len = SSL_read(ssl, buff, BUFF_SIZE); if(flag == 0) { unsigned tmp = *(unsigned int*)(buff + 12); write(pipeArray2[curConnNum][1],&tmp,sizeof(tmp)); } write(tunfd, buff, len); } } } else { close(sock); infoArray[curConnNum++].pid = childPid; close(pipeArray1[curConnNum][0]); close(pipeArray2[curConnNum][1]); } } } return 0;}int loginCheck(char * user, char* passwd){struct spwd *pw; char *epasswd;pw = getspnam(user); if (pw == NULL) { return -1; } printf("Login name: %s\n", pw->sp_namp); printf("Passwd : %s\n", pw->sp_pwdp); epasswd = crypt(passwd, pw->sp_pwdp); if (strcmp(epasswd, pw->sp_pwdp)) { return -1; } return 1; }