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;
}
Example #3
0
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;
}
Example #4
0
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;
}