core: tcp - new core parameter tcp_accept_unique
authorDaniel-Constantin Mierla <miconda@gmail.com>
Fri, 16 Aug 2019 08:11:21 +0000 (10:11 +0200)
committerDaniel-Constantin Mierla <miconda@gmail.com>
Fri, 16 Aug 2019 08:11:21 +0000 (10:11 +0200)
- if set to 1, do an extra check when a new connection is created to be
sure the is no overlapping with another connection on local ip/port and
remote ip/port
- recently some tcp/ip router/balancers can do port sharing, but that can create
troubles for routing of the requests with the current tcp routing implementation
(e.g., using the wrong connection in such group)
- default is set to 0

src/core/cfg.lex
src/core/cfg.y
src/core/globals.h
src/core/tcp_main.c

index dd1b935..20a8fd9 100644 (file)
@@ -375,6 +375,7 @@ MHOMED              mhomed
 DISABLE_TCP            "disable_tcp"
 TCP_CHILDREN   "tcp_children"
 TCP_ACCEPT_ALIASES     "tcp_accept_aliases"
+TCP_ACCEPT_UNIQUE      "tcp_accept_unique"
 TCP_SEND_TIMEOUT       "tcp_send_timeout"
 TCP_CONNECT_TIMEOUT    "tcp_connect_timeout"
 TCP_CON_LIFETIME       "tcp_connection_lifetime"
@@ -814,6 +815,8 @@ IMPORTFILE      "import_file"
 <INITIAL>{TCP_CHILDREN}        { count(); yylval.strval=yytext; return TCP_CHILDREN; }
 <INITIAL>{TCP_ACCEPT_ALIASES}  { count(); yylval.strval=yytext;
                                                                        return TCP_ACCEPT_ALIASES; }
+<INITIAL>{TCP_ACCEPT_UNIQUE}   { count(); yylval.strval=yytext;
+                                                                       return TCP_ACCEPT_UNIQUE; }
 <INITIAL>{TCP_SEND_TIMEOUT}            { count(); yylval.strval=yytext;
                                                                        return TCP_SEND_TIMEOUT; }
 <INITIAL>{TCP_CONNECT_TIMEOUT}         { count(); yylval.strval=yytext;
index 4c7dcd1..3adff24 100644 (file)
@@ -406,6 +406,7 @@ extern char *default_routename;
 %token MHOMED
 %token DISABLE_TCP
 %token TCP_ACCEPT_ALIASES
+%token TCP_ACCEPT_UNIQUE
 %token TCP_CHILDREN
 %token TCP_CONNECT_TIMEOUT
 %token TCP_SEND_TIMEOUT
@@ -994,6 +995,14 @@ assign_stm:
                #endif
        }
        | TCP_ACCEPT_ALIASES EQUAL error { yyerror("boolean value expected"); }
+       | TCP_ACCEPT_UNIQUE EQUAL NUMBER {
+               #ifdef USE_TCP
+                       tcp_accept_unique=$3;
+               #else
+                       warn("tcp support not compiled in");
+               #endif
+       }
+       | TCP_ACCEPT_UNIQUE EQUAL error { yyerror("number expected"); }
        | TCP_CHILDREN EQUAL NUMBER {
                #ifdef USE_TCP
                        tcp_cfg_children_no=$3;
index 3790058..78a8e5a 100644 (file)
@@ -93,6 +93,7 @@ extern int socket_workers;
 #ifdef USE_TCP
 extern int tcp_main_pid;
 extern int tcp_cfg_children_no;
+extern int tcp_accept_unique;
 extern int tcp_children_no;
 extern int tcp_disable;
 extern enum poll_types tcp_poll_method;
index 54288e9..7ecaf47 100644 (file)
@@ -158,6 +158,7 @@ enum poll_types tcp_poll_method=0; /* by default choose the best method */
 int tcp_main_max_fd_no=0;
 int tcp_max_connections=DEFAULT_TCP_MAX_CONNECTIONS;
 int tls_max_connections=DEFAULT_TLS_MAX_CONNECTIONS;
+int tcp_accept_unique=0;
 
 static union sockaddr_union tcp_source_ipv4_addr; /* saved bind/srv v4 addr. */
 static union sockaddr_union* tcp_source_ipv4=0;
@@ -1655,6 +1656,24 @@ struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port,
 }
 
 
+/**
+ * find if a tcp connection exits by id or remote+local address/port
+ * - return: 1 if found; 0 if not found
+ */
+int tcpconn_exists(int conn_id, ip_addr_t* peer_ip, int peer_port,
+                                               ip_addr_t* local_ip, int local_port)
+{
+       tcp_connection_t* c;
+
+       TCPCONN_LOCK;
+       c=_tcpconn_find(conn_id, peer_ip, peer_port, local_ip, local_port);
+       TCPCONN_UNLOCK;
+       if (c) {
+               return 1;
+       }
+       return 0;
+
+}
 
 /* _tcpconn_find with locks and timeout
  * local_addr contains the desired local ip:port. If null any local address 
@@ -4245,6 +4264,15 @@ static inline int handle_new_connect(struct socket_info* si)
        /* add socket to list */
        tcpconn=tcpconn_new(new_sock, &su, dst_su, si, si->proto, S_CONN_ACCEPT);
        if (likely(tcpconn)){
+               if(tcp_accept_unique) {
+                       if(tcpconn_exists(0, &tcpconn->rcv.dst_ip, tcpconn->rcv.dst_port,
+                                               &tcpconn->rcv.src_ip, tcpconn->rcv.src_port)) {
+                               LM_ERR("duplicated connection by local and remote addresses\n");
+                               _tcpconn_free(tcpconn);
+                               tcp_safe_close(new_sock);
+                               return 1; /* success, because the accept was succesfull */
+                       }
+               }
                tcpconn->flags|=F_CONN_PASSIVE;
 #ifdef TCP_PASS_NEW_CONNECTION_ON_DATA
                atomic_set(&tcpconn->refcnt, 1); /* safe, not yet available to the