static int handler_tcp_tun_to_net(int fd, const struct worker_struct *ws, char *buff, size_t len) { int dfd, keep = 1; char *cbuff; ssize_t rlen, err, clen; struct ct_proto *hdr; struct curve25519_proto *p; socklen_t nlen; size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes; if (!buff || len <= off) return 0; memset(buff, 0, len); while ((rlen = read(fd, buff + off, len - off)) > 0) { dfd = -1; p = NULL; hdr = (struct ct_proto *) buff; memset(hdr, 0, sizeof(*hdr)); hdr->flags = 0; trie_addr_lookup(buff + off, rlen, ws->parent.ipv4, &dfd, NULL, (size_t *) &nlen); if (unlikely(dfd < 0)) { memset(buff, 0, len); continue; } err = get_user_by_socket(dfd, &p); if (unlikely(err || !p)) { memset(buff, 0, len); continue; } clen = curve25519_encode(ws->c, p, (unsigned char *) (buff + off - crypto_box_zerobytes), (rlen + crypto_box_zerobytes), (unsigned char **) &cbuff); if (unlikely(clen <= 0)) { memset(buff, 0, len); continue; } hdr->payload = htons((uint16_t) clen); set_tcp_cork(dfd); write_exact(dfd, hdr, sizeof(struct ct_proto), 0); write_exact(dfd, cbuff, clen, 0); set_tcp_uncork(dfd); memset(buff, 0, len); } return keep; }
static int handler_tcp_net_to_tun(int fd, const struct worker_struct *ws, char *buff, size_t len) { int keep = 1, count = 0; char *cbuff; ssize_t rlen, err, clen; struct ct_proto *hdr; struct curve25519_proto *p; if (!buff || !len) return 0; while ((rlen = handler_tcp_read(fd, buff, len)) > 0) { p = NULL; hdr = (struct ct_proto *) buff; if (unlikely(rlen < sizeof(struct ct_proto))) goto close; if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload))) goto close; if (unlikely(ntohs(hdr->payload) == 0)) goto close; if (hdr->flags & PROTO_FLAG_EXIT) { close: remove_user_by_socket(fd); trie_addr_remove(fd); handler_tcp_notify_close(fd); rlen = write(ws->parent.efd, &fd, sizeof(fd)); keep = 0; return keep; } if (hdr->flags & PROTO_FLAG_INIT) { syslog_maybe(auth_log, LOG_INFO, "Got initial userhash " "from remote end!\n"); if (unlikely(rlen - sizeof(*hdr) < sizeof(struct username_struct))) goto close; err = try_register_user_by_socket(ws->c, buff + sizeof(struct ct_proto), rlen - sizeof(struct ct_proto), fd, auth_log); if (unlikely(err)) goto close; continue; } err = get_user_by_socket(fd, &p); if (unlikely(err || !p)) continue; clen = curve25519_decode(ws->c, p, (unsigned char *) buff + sizeof(struct ct_proto), rlen - sizeof(struct ct_proto), (unsigned char **) &cbuff, NULL); if (unlikely(clen <= 0)) continue; cbuff += crypto_box_zerobytes; clen -= crypto_box_zerobytes; err = trie_addr_maybe_update(cbuff, clen, ws->parent.ipv4, fd, NULL, 0); if (unlikely(err)) continue; err = write(ws->parent.tunfd, cbuff, clen); count++; if (count == 10) { write_exact(ws->efd[1], &fd, sizeof(fd), 1); /* Read later next data and let others process */ return keep; } } return keep; }
static int handler_tcp_tun_to_net(int fd, const struct worker_struct *ws, char *buff, size_t len) { int dfd, state, keep = 1; char *cbuff; ssize_t rlen, err, clen; struct ct_proto *hdr; struct curve25519_proto *p; socklen_t nlen; size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes; if (!buff || len <= off) { errno = EINVAL; return 0; } errno = 0; memset(buff, 0, len); while ((rlen = read(fd, buff + off, len - off)) > 0) { dfd = -1; p = NULL; hdr = (struct ct_proto *) buff; memset(hdr, 0, sizeof(*hdr)); hdr->flags = 0; trie_addr_lookup(buff + off, rlen, ws->parent.ipv4, &dfd, NULL, (size_t *) &nlen); if (unlikely(dfd < 0)) { syslog(LOG_INFO, "CPU%u: TCP tunnel lookup failed: " "unknown destination\n", ws->cpu); memset(buff, 0, len); continue; } err = get_user_by_socket(dfd, &p); if (unlikely(err || !p)) { syslog(LOG_ERR, "CPU%u: User protocol not in cache! " "Dropping connection!\n", ws->cpu); memset(buff, 0, len); continue; } clen = curve25519_encode(ws->c, p, (unsigned char *) (buff + off - crypto_box_zerobytes), (rlen + crypto_box_zerobytes), (unsigned char **) &cbuff); if (unlikely(clen <= 0)) { syslog(LOG_ERR, "CPU%u: TCP tunnel encrypt error: %zd\n", ws->cpu, clen); memset(buff, 0, len); continue; } hdr->payload = htons((uint16_t) clen); state = 1; setsockopt(dfd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state)); err = write_exact(dfd, hdr, sizeof(struct ct_proto), 0); if (unlikely(err < 0)) syslog(LOG_ERR, "CPU%u: TCP tunnel write error: %s\n", ws->cpu, strerror(errno)); err = write_exact(dfd, cbuff, clen, 0); if (unlikely(err < 0)) syslog(LOG_ERR, "CPU%u: TCP tunnel write error: %s\n", ws->cpu, strerror(errno)); state = 0; setsockopt(dfd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state)); errno = 0; memset(buff, 0, len); } if (unlikely(rlen < 0 && errno != EAGAIN)) syslog(LOG_ERR, "CPU%u: TCP tunnel read error: %s\n", ws->cpu, strerror(errno)); return keep; }
static int handler_tcp_net_to_tun(int fd, const struct worker_struct *ws, char *buff, size_t len) { int keep = 1, count = 0; char *cbuff; ssize_t rlen, err, clen; struct ct_proto *hdr; struct curve25519_proto *p; if (!buff || !len) { errno = EINVAL; return 0; } errno = 0; while ((rlen = handler_tcp_read(fd, buff, len)) > 0) { p = NULL; hdr = (struct ct_proto *) buff; if (unlikely(rlen < sizeof(struct ct_proto))) goto close; if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload))) goto close; if (unlikely(ntohs(hdr->payload) == 0)) goto close; if (hdr->flags & PROTO_FLAG_EXIT) { close: remove_user_by_socket(fd); trie_addr_remove(fd); handler_tcp_notify_close(fd); rlen = write(ws->parent.efd, &fd, sizeof(fd)); if (rlen != sizeof(fd)) syslog(LOG_ERR, "CPU%u: TCP event write error: %s\n", ws->cpu, strerror(errno)); keep = 0; return keep; } if (hdr->flags & PROTO_FLAG_INIT) { if (auth_log) syslog(LOG_INFO, "Got initial userhash from remote end!\n"); if (unlikely(rlen - sizeof(*hdr) < sizeof(struct username_struct))) goto close; err = try_register_user_by_socket(ws->c, buff + sizeof(struct ct_proto), rlen - sizeof(struct ct_proto), fd, auth_log); if (unlikely(err)) goto close; continue; } err = get_user_by_socket(fd, &p); if (unlikely(err || !p)) { syslog(LOG_ERR, "CPU%u: User protocol not in cache! " "Dropping connection!\n", ws->cpu); goto close; } clen = curve25519_decode(ws->c, p, (unsigned char *) buff + sizeof(struct ct_proto), rlen - sizeof(struct ct_proto), (unsigned char **) &cbuff, NULL); if (unlikely(clen <= 0)) { syslog(LOG_ERR, "CPU%u: TCP net decryption error: %zd\n", ws->cpu, clen); goto close; } cbuff += crypto_box_zerobytes; clen -= crypto_box_zerobytes; err = trie_addr_maybe_update(cbuff, clen, ws->parent.ipv4, fd, NULL, 0); if (unlikely(err)) { syslog(LOG_INFO, "CPU%u: Malicious packet dropped " "from id %d\n", ws->cpu, fd); continue; } err = write(ws->parent.tunfd, cbuff, clen); if (unlikely(err < 0)) syslog(LOG_ERR, "CPU%u: TCP net write error: %s\n", ws->cpu, strerror(errno)); count++; if (count == 10) { err = write_exact(ws->efd[1], &fd, sizeof(fd), 1); if (unlikely(err != sizeof(fd))) syslog(LOG_ERR, "CPU%u: TCP net put fd back in " "pipe error: %s\n", ws->cpu, strerror(errno)); return keep; } errno = 0; } if (unlikely(rlen < 0 && errno != EAGAIN && errno != EBADF)) syslog(LOG_ERR, "CPU%u: TCP net read error: %s\n", ws->cpu, strerror(errno)); return keep; }
int main(int argc, char** argv) { if (argc != 2) { fprintf(stderr, "usage: RE216_SERVER port\n"); return 1; } // Initialization of the server address struct sockaddr_in serv_addr; int port = atoi(argv[1]); serv_addr.sin_addr.s_addr=htonl(INADDR_ANY); serv_addr.sin_family=AF_INET; serv_addr.sin_port=htons(port); //Creation of the socket int socket; socket=do_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Binding do_bind(socket,serv_addr,sizeof(serv_addr)); // Specify the socket to be a server socket and listen for at most 20 concurrent client listen(socket,20); // Initialization of the select() parameters fd_set my_fd_set; fd_set fd_temp; FD_ZERO(&my_fd_set); FD_SET(socket,&my_fd_set); // adding the server socket to my_fd_set int max_fd = socket+1; //Initialization of the user list storing user profiles created after the accept() function. puser user_list = NULL; char* name_by_default; // Initialization of all the buffers and variables used in all the following options int size_buffer = 300; char* who_is_nick; //Variable used in for loop for browsing through the user list int k; /* Infinite loop */ for (;;) { fd_temp=my_fd_set; // select() is used to get the active sockets : Client or Server int select_temp; select_temp = select(max_fd,&fd_temp,NULL,NULL,NULL); int i; for(i=3;i<max_fd;i++) { if(FD_ISSET(i, &fd_temp)) { // New connections management if(i==socket) { // Accepting connections from the differents clients int new_sock_client; new_sock_client = do_accept(socket,serv_addr,sizeof(serv_addr)); printf("CLIENT %d IS NOW CONNECTED ON THE CHAT ! \n",new_sock_client-socket); if (max_fd <= new_sock_client) max_fd = new_sock_client +1; FD_SET(new_sock_client,&my_fd_set); // Adding the new socket to my_fd_set // Creating a new user profile struct user new_user; strcpy(new_user.name,"Client"); new_user.socket_client = new_sock_client; new_user.next_user = user_list; // Connection Data Management char buffer[512]; char date_hour[40]; /* Date and hour management */ time_t timer_seconds = time(NULL); struct tm * timeinfo = localtime(&timer_seconds); // /whois <nickname> displaying management strftime(date_hour, sizeof(date_hour), "%d/%m/%Y@%H:%M", timeinfo); sprintf(buffer,"%s WITH IP ADDRESS 127.0.0.1 AND PORT %d \n",date_hour,port); strcpy(new_user.connect_data,buffer); // Add a new user to the user_list user_list = add_user(user_list,new_user); } // Client management else { // Initialization of the buffer for incomming and outcomming information about any client char buffer_client[size_buffer]; bzero(buffer_client,size_buffer); // Get user information for the profile by the socket puser user = get_user_by_socket(user_list,i); // Read the sending message of the client /*Receive the message from the socket by using recv */ int tempo_recvs=recv(i,buffer_client,size_buffer,0); if (tempo_recvs != -1 && strncmp(buffer_client,"/quit\n",6) && strcmp(user->name,"Client") && strncmp(buffer_client,"/nick ",6) && strncmp(buffer_client,"/who\n",5) && strncmp(buffer_client,"/whois ",7)) { printf("[%s]: %s",user->name, buffer_client); } else if(tempo_recvs==-1){ printf("ERROR : AN ERROR OCCURED WHILE RECEIVING MESSAGE \n"); perror("recv"); exit(EXIT_FAILURE); } // /nick management if(strncmp(buffer_client,"/nick ",6)==0) { // Get the client input and remove the segmentation fault name_by_default = strchr(buffer_client,' ') +sizeof(char); strcpy(name_by_default+(strlen(name_by_default)-1)*sizeof(char),"\0"); int already_used=0; // We browse through the user list in order to check if the nickname chosen by the Client is already used for(k=4;k<max_fd;k++) { if (k != i) { puser nickuser = get_user_by_socket(user_list,k); if(strcmp(nickuser->name,name_by_default)==0){ strcpy(buffer_client,"ERROR : NICKNAME ALREADY USED ! \n"); already_used=1; break; } } } // If the nickname chosen by the Client isn't already used if(already_used!=1 && strcmp(user->name,name_by_default)) { // When a Client visit the chat for the first time if (!strcmp(user->name,"Client")) { strcpy(user->name,name_by_default); sprintf(buffer_client,"WELCOME ON THE CHAT %s \n",user->name); printf("[SERVER]: %s",buffer_client); } // If a Client is already connected on the chat with a nickname but he used /nick again, he can change his nickname else { printf("[SERVER]: %s IS NOW KNOWN AS %s \n",user->name,name_by_default); strcpy(user->name,name_by_default); sprintf(buffer_client,"YOUR NEW NICKNAME IS %s \n",user->name); } } do_send_server(i, buffer_client, size_buffer); } // If a Client doesn't have a nickname yet, he can't talk on the chat else if(strcmp(user->name,"Client")==0) { strcpy(buffer_client,"ERROR : YOU MUST CHOOSE A NICKNAME BY USING /nick BEFORE CHATTING ! \n"); do_send_server(i, buffer_client, size_buffer); } // /who management else if(strncmp(buffer_client,"/who\n",5)==0) { strcpy(buffer_client,"MORE INFORMATION ABOUT ONLINE USERS -> THESE CLIENTS ARE CURRENTLY ONLINE :\n"); for(k=4;k<max_fd;k++){ puser whouser = get_user_by_socket(user_list,k); if (strcmp(whouser->name,"Client")){ char who_name[60]; sprintf(who_name," %s \n",whouser->name); strcat(buffer_client,who_name); } } do_send_server(i, buffer_client, size_buffer); } // /whois management else if(strncmp(buffer_client,"/whois ",7)==0) { who_is_nick = strchr(buffer_client,' ') +sizeof(char); strcpy(who_is_nick+(strlen(who_is_nick)-1)*sizeof(char),"\0"); puser whois_user; whois_user = get_user_by_name(user_list,who_is_nick); if (whois_user != NULL) { sprintf(buffer_client,"MORE INFORMATION ABOUT CLIENT %s : HE IS CONNECTED SINCE %s \n", whois_user->name, whois_user->connect_data); } else{ strcpy(buffer_client,"ERROR : THERE IS NO ANY CLIENTS CONNECTED \n"); } do_send_server(i, buffer_client, size_buffer); } // /quit management else if(strncmp(buffer_client,"/quit\n",6)==0) { close(i); FD_CLR(i,&my_fd_set); printf("[SERVER]: %s JUST LEFT THE CHAT -> THE CLIENT %d IS DISCONNECTED ! \n",user->name,user->socket_client-socket); break; } //Sending back message to client else { strcpy(buffer_client,"\0"); do_send_server(i, buffer_client, size_buffer); } } } } } // Closing socket close(socket); return 0; }