Module: kamailio
Branch: master
Commit: a902e4a032a85a7755de32eeadac800a1312e64f
URL:
https://github.com/kamailio/kamailio/commit/a902e4a032a85a7755de32eeadac800…
Author: Daniel-Constantin Mierla <miconda(a)gmail.com>
Committer: Daniel-Constantin Mierla <miconda(a)gmail.com>
Date: 2023-10-13T17:33:51+02:00
core: tcp - limit number of accepted connections per src ip
- default 1024
---
Modified: src/core/tcp_conn.h
Modified: src/core/tcp_main.c
Modified: src/core/tcp_read.c
---
Diff:
https://github.com/kamailio/kamailio/commit/a902e4a032a85a7755de32eeadac800…
Patch:
https://github.com/kamailio/kamailio/commit/a902e4a032a85a7755de32eeadac800…
---
diff --git a/src/core/tcp_conn.h b/src/core/tcp_conn.h
index 4cb3da51f40..2a4a2dd7b0d 100644
--- a/src/core/tcp_conn.h
+++ b/src/core/tcp_conn.h
@@ -47,6 +47,8 @@
#define KSR_TCP_MSGREAD_TIMEOUT 20 /* timeout (secs) to read SIP message */
+#define KSR_TCP_ACCEPT_IPLIMIT 1024 /* limit accepted tcp connections from IP */
+
/* tcp connection flags */
#define F_CONN_READ_W 2 /* watched for READ ev. in main */
#define F_CONN_WRITE_W 4 /* watched for WRITE (main) */
@@ -281,6 +283,7 @@ typedef struct tcp_connection
unsigned int flags; /* connection related flags */
snd_flags_t send_flags; /* special send flags */
enum tcp_conn_states state; /* connection state */
+ enum tcp_conn_states initstate; /* initial connection state */
void *extra_data; /* extra data associated to the connection, 0 for tcp*/
struct timer_ln timer;
time_t timestamp; /* connection creation timestamp */
diff --git a/src/core/tcp_main.c b/src/core/tcp_main.c
index 9f39dd72444..aac5347431d 100644
--- a/src/core/tcp_main.c
+++ b/src/core/tcp_main.c
@@ -1162,6 +1162,30 @@ int tcpconn_read_haproxy(struct tcp_connection *c)
return (bytes >= 0) ? retval : -1;
}
+int tcp_connection_limit_srcip(union sockaddr_union *srcaddr, int limit)
+{
+ struct tcp_connection *con;
+ ip_addr_t src_ip;
+ int n;
+ int i;
+
+ n = 0;
+ su2ip_addr(&src_ip, srcaddr);
+ TCPCONN_LOCK;
+ for(i = 0; i < TCP_ID_HASH_SIZE && n < limit; i++) {
+ for(con = tcpconn_id_hash[i]; con && n < limit; con = con->id_next) {
+ if(con->initstate == S_CONN_ACCEPT) {
+ if(ip_addr_cmp(&src_ip, &con->rcv.src_ip)) {
+ n++;
+ }
+ }
+ }
+ }
+ TCPCONN_UNLOCK;
+
+ return (n >= limit) ? 1 : 0;
+}
+
struct tcp_connection *tcpconn_new(int sock, union sockaddr_union *su,
union sockaddr_union *local_addr, struct socket_info *ba, int type,
int state)
@@ -1217,6 +1241,7 @@ struct tcp_connection *tcpconn_new(int sock, union sockaddr_union
*su,
c->rcv.proto_reserved1 = 0; /* this will be filled before receive_message*/
c->rcv.proto_reserved2 = 0;
c->state = state;
+ c->initstate = state;
c->extra_data = 0;
c->timestamp = time(NULL);
#ifdef USE_TLS
@@ -4426,6 +4451,12 @@ static inline int handle_new_connect(struct socket_info *si)
tcp_safe_close(new_sock);
return 1; /* success, because the accept was successful */
}
+ if(unlikely(tcp_connection_limit_srcip(&su, KSR_TCP_ACCEPT_IPLIMIT))) {
+ LM_CRIT("hit the limit of connections per source IP (%s) - rejecting\n",
+ su2a(&su, sizeof(su)));
+ tcp_safe_close(new_sock);
+ return 1; /* success, because the accept was successful */
+ }
(*tcp_connections_no)++;
if(unlikely(si->proto == PROTO_TLS))
(*tls_connections_no)++;
diff --git a/src/core/tcp_read.c b/src/core/tcp_read.c
index 2ad9579854f..31c6e92444c 100644
--- a/src/core/tcp_read.c
+++ b/src/core/tcp_read.c
@@ -448,7 +448,6 @@ int tcp_read_headers(struct tcp_connection *c, rd_conn_flags_t
*read_flags)
bytes = tcp_read(c, read_flags);
if(bytes <= 0)
return bytes;
- LM_DBG("===== read %d bytes\n", bytes);
gettimeofday(&tvnow, NULL);
tvdiff = 1000000 * (tvnow.tv_sec - r->tvrstart.tv_sec)
+ (tvnow.tv_usec - r->tvrstart.tv_usec);
@@ -1661,12 +1660,10 @@ int tcp_read_req(struct tcp_connection *con, int *bytes_read,
req->content_len = 0;
req->bytes_to_go = 0;
req->pos = req->buf + size;
- LM_DBG("=== reset message read start time\n");
req->tvrstart.tv_sec = 0;
req->tvrstart.tv_usec = 0;
if(unlikely(size)) {
- LM_DBG("=== set message read start time\n");
gettimeofday(&req->tvrstart, NULL);
memmove(req->buf, req->parsed, size);
req->parsed = req->buf; /* fix req->parsed after using it */