diff options
author | Amerigo Wang <amwang@redhat.com> | 2010-05-04 20:27:06 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-05-16 02:28:40 -0400 |
commit | e3826f1e946e7d2354943232f1457be1455a29e2 (patch) | |
tree | a34055c7de762410b6a10c21ab5e1999fb38803b | |
parent | 9f977fb7ae9ddf565b4800854212fb9a1ed6c2ea (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.txt | 31 | ||||
-rw-r--r-- | include/net/ip.h | 6 | ||||
-rw-r--r-- | net/ipv4/af_inet.c | 8 | ||||
-rw-r--r-- | net/ipv4/inet_connection_sock.c | 6 | ||||
-rw-r--r-- | net/ipv4/inet_hashtables.c | 2 | ||||
-rw-r--r-- | net/ipv4/sysctl_net_ipv4.c | 17 | ||||
-rw-r--r-- | net/ipv4/udp.c | 3 | ||||
-rw-r--r-- | net/sctp/socket.c | 2 |
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 | ||
591 | ip_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 | |||
591 | ip_nonlocal_bind - BOOLEAN | 622 | ip_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; |
185 | extern void inet_get_local_port_range(int *low, int *high); | 185 | extern void inet_get_local_port_range(int *low, int *high); |
186 | 186 | ||
187 | extern unsigned long *sysctl_local_reserved_ports; | ||
188 | static inline int inet_is_reserved_local_port(int port) | ||
189 | { | ||
190 | return test_bit(port, sysctl_local_reserved_ports); | ||
191 | } | ||
192 | |||
187 | extern int sysctl_ip_default_ttl; | 193 | extern int sysctl_ip_default_ttl; |
188 | extern int sysctl_ip_nonlocal_bind; | 194 | extern 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); |
1675 | out_unregister_tcp_proto: | 1679 | out_unregister_tcp_proto: |
1676 | proto_unregister(&tcp_prot); | 1680 | proto_unregister(&tcp_prot); |
1681 | out_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 | ||
40 | unsigned long *sysctl_local_reserved_ports; | ||
41 | EXPORT_SYMBOL(sysctl_local_reserved_ports); | ||
42 | |||
40 | void inet_get_local_port_range(int *low, int *high) | 43 | void 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 = { | |||
736 | static __init int sysctl_ipv4_init(void) | 743 | static __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); |