aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmerigo Wang <amwang@redhat.com>2010-05-04 20:27:06 -0400
committerDavid S. Miller <davem@davemloft.net>2010-05-16 02:28:40 -0400
commite3826f1e946e7d2354943232f1457be1455a29e2 (patch)
treea34055c7de762410b6a10c21ab5e1999fb38803b
parent9f977fb7ae9ddf565b4800854212fb9a1ed6c2ea (diff)
net: reserve ports for applications using fixed port numbers
(Dropped the infiniband part, because Tetsuo modified the related code, I will send a separate patch for it once this is accepted.) This patch introduces /proc/sys/net/ipv4/ip_local_reserved_ports which allows users to reserve ports for third-party applications. The reserved ports will not be used by automatic port assignments (e.g. when calling connect() or bind() with port number 0). Explicit port allocation behavior is unchanged. Signed-off-by: Octavian Purdila <opurdila@ixiacom.com> Signed-off-by: WANG Cong <amwang@redhat.com> Cc: Neil Horman <nhorman@tuxdriver.com> Cc: Eric Dumazet <eric.dumazet@gmail.com> Cc: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/networking/ip-sysctl.txt31
-rw-r--r--include/net/ip.h6
-rw-r--r--net/ipv4/af_inet.c8
-rw-r--r--net/ipv4/inet_connection_sock.c6
-rw-r--r--net/ipv4/inet_hashtables.c2
-rw-r--r--net/ipv4/sysctl_net_ipv4.c17
-rw-r--r--net/ipv4/udp.c3
-rw-r--r--net/sctp/socket.c2
8 files changed, 73 insertions, 2 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 8b72c88ba213..d0536b5a4e01 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -588,6 +588,37 @@ ip_local_port_range - 2 INTEGERS
588 (i.e. by default) range 1024-4999 is enough to issue up to 588 (i.e. by default) range 1024-4999 is enough to issue up to
589 2000 connections per second to systems supporting timestamps. 589 2000 connections per second to systems supporting timestamps.
590 590
591ip_local_reserved_ports - list of comma separated ranges
592 Specify the ports which are reserved for known third-party
593 applications. These ports will not be used by automatic port
594 assignments (e.g. when calling connect() or bind() with port
595 number 0). Explicit port allocation behavior is unchanged.
596
597 The format used for both input and output is a comma separated
598 list of ranges (e.g. "1,2-4,10-10" for ports 1, 2, 3, 4 and
599 10). Writing to the file will clear all previously reserved
600 ports and update the current list with the one given in the
601 input.
602
603 Note that ip_local_port_range and ip_local_reserved_ports
604 settings are independent and both are considered by the kernel
605 when determining which ports are available for automatic port
606 assignments.
607
608 You can reserve ports which are not in the current
609 ip_local_port_range, e.g.:
610
611 $ cat /proc/sys/net/ipv4/ip_local_port_range
612 32000 61000
613 $ cat /proc/sys/net/ipv4/ip_local_reserved_ports
614 8080,9148
615
616 although this is redundant. However such a setting is useful
617 if later the port range is changed to a value that will
618 include the reserved ports.
619
620 Default: Empty
621
591ip_nonlocal_bind - BOOLEAN 622ip_nonlocal_bind - BOOLEAN
592 If set, allows processes to bind() to non-local IP addresses, 623 If set, allows processes to bind() to non-local IP addresses,
593 which can be quite useful - but may break some applications. 624 which can be quite useful - but may break some applications.
diff --git a/include/net/ip.h b/include/net/ip.h
index 8149b77cea9b..63548f0a44b1 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -184,6 +184,12 @@ extern struct local_ports {
184} sysctl_local_ports; 184} sysctl_local_ports;
185extern void inet_get_local_port_range(int *low, int *high); 185extern void inet_get_local_port_range(int *low, int *high);
186 186
187extern unsigned long *sysctl_local_reserved_ports;
188static inline int inet_is_reserved_local_port(int port)
189{
190 return test_bit(port, sysctl_local_reserved_ports);
191}
192
187extern int sysctl_ip_default_ttl; 193extern int sysctl_ip_default_ttl;
188extern int sysctl_ip_nonlocal_bind; 194extern int sysctl_ip_nonlocal_bind;
189 195
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index c6c43bcd1c6f..551ce564b035 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1573,9 +1573,13 @@ static int __init inet_init(void)
1573 1573
1574 BUILD_BUG_ON(sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)); 1574 BUILD_BUG_ON(sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb));
1575 1575
1576 sysctl_local_reserved_ports = kzalloc(65536 / 8, GFP_KERNEL);
1577 if (!sysctl_local_reserved_ports)
1578 goto out;
1579
1576 rc = proto_register(&tcp_prot, 1); 1580 rc = proto_register(&tcp_prot, 1);
1577 if (rc) 1581 if (rc)
1578 goto out; 1582 goto out_free_reserved_ports;
1579 1583
1580 rc = proto_register(&udp_prot, 1); 1584 rc = proto_register(&udp_prot, 1);
1581 if (rc) 1585 if (rc)
@@ -1674,6 +1678,8 @@ out_unregister_udp_proto:
1674 proto_unregister(&udp_prot); 1678 proto_unregister(&udp_prot);
1675out_unregister_tcp_proto: 1679out_unregister_tcp_proto:
1676 proto_unregister(&tcp_prot); 1680 proto_unregister(&tcp_prot);
1681out_free_reserved_ports:
1682 kfree(sysctl_local_reserved_ports);
1677 goto out; 1683 goto out;
1678} 1684}
1679 1685
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index e0a3e3537b14..70eb3507c406 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -37,6 +37,9 @@ struct local_ports sysctl_local_ports __read_mostly = {
37 .range = { 32768, 61000 }, 37 .range = { 32768, 61000 },
38}; 38};
39 39
40unsigned long *sysctl_local_reserved_ports;
41EXPORT_SYMBOL(sysctl_local_reserved_ports);
42
40void inet_get_local_port_range(int *low, int *high) 43void inet_get_local_port_range(int *low, int *high)
41{ 44{
42 unsigned seq; 45 unsigned seq;
@@ -108,6 +111,8 @@ again:
108 111
109 smallest_size = -1; 112 smallest_size = -1;
110 do { 113 do {
114 if (inet_is_reserved_local_port(rover))
115 goto next_nolock;
111 head = &hashinfo->bhash[inet_bhashfn(net, rover, 116 head = &hashinfo->bhash[inet_bhashfn(net, rover,
112 hashinfo->bhash_size)]; 117 hashinfo->bhash_size)];
113 spin_lock(&head->lock); 118 spin_lock(&head->lock);
@@ -130,6 +135,7 @@ again:
130 break; 135 break;
131 next: 136 next:
132 spin_unlock(&head->lock); 137 spin_unlock(&head->lock);
138 next_nolock:
133 if (++rover > high) 139 if (++rover > high)
134 rover = low; 140 rover = low;
135 } while (--remaining > 0); 141 } while (--remaining > 0);
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 2b79377b468d..d3e160a88219 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -456,6 +456,8 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
456 local_bh_disable(); 456 local_bh_disable();
457 for (i = 1; i <= remaining; i++) { 457 for (i = 1; i <= remaining; i++) {
458 port = low + (i + offset) % remaining; 458 port = low + (i + offset) % remaining;
459 if (inet_is_reserved_local_port(port))
460 continue;
459 head = &hinfo->bhash[inet_bhashfn(net, port, 461 head = &hinfo->bhash[inet_bhashfn(net, port,
460 hinfo->bhash_size)]; 462 hinfo->bhash_size)];
461 spin_lock(&head->lock); 463 spin_lock(&head->lock);
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 1cd5c15174b8..d96c1da4b17c 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -299,6 +299,13 @@ static struct ctl_table ipv4_table[] = {
299 .mode = 0644, 299 .mode = 0644,
300 .proc_handler = ipv4_local_port_range, 300 .proc_handler = ipv4_local_port_range,
301 }, 301 },
302 {
303 .procname = "ip_local_reserved_ports",
304 .data = NULL, /* initialized in sysctl_ipv4_init */
305 .maxlen = 65536,
306 .mode = 0644,
307 .proc_handler = proc_do_large_bitmap,
308 },
302#ifdef CONFIG_IP_MULTICAST 309#ifdef CONFIG_IP_MULTICAST
303 { 310 {
304 .procname = "igmp_max_memberships", 311 .procname = "igmp_max_memberships",
@@ -736,6 +743,16 @@ static __net_initdata struct pernet_operations ipv4_sysctl_ops = {
736static __init int sysctl_ipv4_init(void) 743static __init int sysctl_ipv4_init(void)
737{ 744{
738 struct ctl_table_header *hdr; 745 struct ctl_table_header *hdr;
746 struct ctl_table *i;
747
748 for (i = ipv4_table; i->procname; i++) {
749 if (strcmp(i->procname, "ip_local_reserved_ports") == 0) {
750 i->data = sysctl_local_reserved_ports;
751 break;
752 }
753 }
754 if (!i->procname)
755 return -EINVAL;
739 756
740 hdr = register_sysctl_paths(net_ipv4_ctl_path, ipv4_table); 757 hdr = register_sysctl_paths(net_ipv4_ctl_path, ipv4_table);
741 if (hdr == NULL) 758 if (hdr == NULL)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index f3e00c5cd1ed..9de6a698f91d 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -233,7 +233,8 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
233 */ 233 */
234 do { 234 do {
235 if (low <= snum && snum <= high && 235 if (low <= snum && snum <= high &&
236 !test_bit(snum >> udptable->log, bitmap)) 236 !test_bit(snum >> udptable->log, bitmap) &&
237 !inet_is_reserved_local_port(snum))
237 goto found; 238 goto found;
238 snum += rand; 239 snum += rand;
239 } while (snum != first); 240 } while (snum != first);
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index ba1add0b13c3..ca44917872d2 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -5433,6 +5433,8 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
5433 rover++; 5433 rover++;
5434 if ((rover < low) || (rover > high)) 5434 if ((rover < low) || (rover > high))
5435 rover = low; 5435 rover = low;
5436 if (inet_is_reserved_local_port(rover))
5437 continue;
5436 index = sctp_phashfn(rover); 5438 index = sctp_phashfn(rover);
5437 head = &sctp_port_hashtable[index]; 5439 head = &sctp_port_hashtable[index];
5438 sctp_spin_lock(&head->lock); 5440 sctp_spin_lock(&head->lock);