Bläddra i källkod

[udp] Verify local socket address (if specified) for UDP sockets

UDP sockets can be used for multicast, at which point it becomes
plausible that we could receive packets that aren't destined for us
but that still match on a port number.
tags/v0.9.4
Michael Brown 16 år sedan
förälder
incheckning
aa160211c2
2 ändrade filer med 38 tillägg och 22 borttagningar
  1. 9
    0
      src/include/gpxe/in.h
  2. 29
    22
      src/net/udp.c

+ 9
- 0
src/include/gpxe/in.h Visa fil

@@ -62,6 +62,15 @@ struct sockaddr_in {
62 62
 	uint16_t sin_port;
63 63
 	/** IPv4 address */
64 64
 	struct in_addr sin_addr;
65
+	/** Padding
66
+	 *
67
+	 * This ensures that a struct @c sockaddr_tcpip is large
68
+	 * enough to hold a socket address for any TCP/IP address
69
+	 * family.
70
+	 */
71
+	char pad[ sizeof ( struct sockaddr ) - sizeof ( sa_family_t )
72
+					     - sizeof ( uint16_t )
73
+					     - sizeof ( struct in_addr ) ];
65 74
 };
66 75
 
67 76
 /**

+ 29
- 22
src/net/udp.c Visa fil

@@ -29,10 +29,10 @@ struct udp_connection {
29 29
 	/** Data transfer interface */
30 30
 	struct xfer_interface xfer;
31 31
 
32
+	/** Local socket address */
33
+	struct sockaddr_tcpip local;
32 34
 	/** Remote socket address */
33 35
 	struct sockaddr_tcpip peer;
34
-	/** Local port on which the connection receives packets */
35
-	unsigned int local_port;
36 36
 };
37 37
 
38 38
 /**
@@ -48,22 +48,22 @@ struct tcpip_protocol udp_protocol;
48 48
  * Bind UDP connection to local port
49 49
  *
50 50
  * @v udp		UDP connection
51
- * @v port		Local port, in network byte order, or zero
52 51
  * @ret rc		Return status code
53 52
  *
54
- * Opens the UDP connection and binds to a local port.  If no local
55
- * port is specified, the first available port will be used.
53
+ * Opens the UDP connection and binds to the specified local port.  If
54
+ * no local port is specified, the first available port will be used.
56 55
  */
57
-static int udp_bind ( struct udp_connection *udp, unsigned int port ) {
56
+static int udp_bind ( struct udp_connection *udp ) {
58 57
 	struct udp_connection *existing;
59 58
 	static uint16_t try_port = 1024;
60 59
 
61 60
 	/* If no port specified, find the first available port */
62
-	if ( ! port ) {
61
+	if ( ! udp->local.st_port ) {
63 62
 		for ( ; try_port ; try_port++ ) {
64 63
 			if ( try_port < 1024 )
65 64
 				continue;
66
-			if ( udp_bind ( udp, htons ( try_port ) ) == 0 )
65
+			udp->local.st_port = htons ( try_port );
66
+			if ( udp_bind ( udp ) == 0 )
67 67
 				return 0;
68 68
 		}
69 69
 		return -EADDRINUSE;
@@ -71,16 +71,16 @@ static int udp_bind ( struct udp_connection *udp, unsigned int port ) {
71 71
 
72 72
 	/* Attempt bind to local port */
73 73
 	list_for_each_entry ( existing, &udp_conns, list ) {
74
-		if ( existing->local_port == port ) {
74
+		if ( existing->local.st_port == udp->local.st_port ) {
75 75
 			DBGC ( udp, "UDP %p could not bind: port %d in use\n",
76
-			       udp, ntohs ( port ) );
76
+			       udp, ntohs ( udp->local.st_port ) );
77 77
 			return -EADDRINUSE;
78 78
 		}
79 79
 	}
80
-	udp->local_port = port;
81 80
 
82 81
 	/* Add to UDP connection list */
83
-	DBGC ( udp, "UDP %p bound to port %d\n", udp, ntohs ( port ) );
82
+	DBGC ( udp, "UDP %p bound to port %d\n",
83
+	       udp, ntohs ( udp->local.st_port ) );
84 84
 
85 85
 	return 0;
86 86
 }
@@ -100,7 +100,6 @@ static int udp_open_common ( struct xfer_interface *xfer,
100 100
 	struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
101 101
 	struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
102 102
 	struct udp_connection *udp;
103
-	unsigned int bind_port;
104 103
 	int rc;
105 104
 
106 105
 	/* Allocate and initialise structure */
@@ -111,11 +110,12 @@ static int udp_open_common ( struct xfer_interface *xfer,
111 110
 	xfer_init ( &udp->xfer, &udp_xfer_operations, &udp->refcnt );
112 111
 	if ( st_peer )
113 112
 		memcpy ( &udp->peer, st_peer, sizeof ( udp->peer ) );
113
+	if ( st_local )
114
+		memcpy ( &udp->local, st_local, sizeof ( udp->local ) );
114 115
 
115 116
 	/* Bind to local port */
116 117
 	if ( ! promisc ) {
117
-		bind_port = ( st_local ? st_local->st_port : 0 );
118
-		if ( ( rc = udp_bind ( udp, bind_port ) ) != 0 )
118
+		if ( ( rc = udp_bind ( udp ) ) != 0 )
119 119
 			goto err;
120 120
 	}
121 121
 
@@ -201,7 +201,7 @@ static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
201 201
 
202 202
 	/* Fill in default values if not explicitly provided */
203 203
 	if ( ! src_port )
204
-		src_port = udp->local_port;
204
+		src_port = udp->local.st_port;
205 205
 	if ( ! dest )
206 206
 		dest = &udp->peer;
207 207
 
@@ -231,17 +231,24 @@ static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
231 231
 }
232 232
 
233 233
 /**
234
- * Identify UDP connection by local port number
234
+ * Identify UDP connection by local address
235 235
  *
236
- * @v local_port	Local port (in network-endian order)
236
+ * @v local		Local address
237 237
  * @ret udp		UDP connection, or NULL
238 238
  */
239
-static struct udp_connection * udp_demux ( unsigned int local_port ) {
239
+static struct udp_connection * udp_demux ( struct sockaddr_tcpip *local ) {
240
+	static const struct sockaddr_tcpip empty_sockaddr;
240 241
 	struct udp_connection *udp;
241 242
 
242 243
 	list_for_each_entry ( udp, &udp_conns, list ) {
243
-		if ( ( udp->local_port == local_port ) ||
244
-		     ( udp->local_port == 0 ) ) {
244
+		if ( ( ( udp->local.st_family == local->st_family ) ||
245
+		       ( udp->local.st_family == 0 ) ) &&
246
+		     ( ( udp->local.st_port == local->st_port ) ||
247
+		       ( udp->local.st_port == 0 ) ) &&
248
+		     ( ( memcmp ( udp->local.pad, local->pad,
249
+				  sizeof ( udp->local.pad ) ) == 0 ) ||
250
+		       ( memcmp ( udp->local.pad, empty_sockaddr.pad,
251
+				  sizeof ( udp->local.pad ) ) == 0 ) ) ) {
245 252
 			return udp;
246 253
 		}
247 254
 	}
@@ -300,7 +307,7 @@ static int udp_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
300 307
 	/* Parse parameters from header and strip header */
301 308
 	st_src->st_port = udphdr->src;
302 309
 	st_dest->st_port = udphdr->dest;
303
-	udp = udp_demux ( udphdr->dest );
310
+	udp = udp_demux ( st_dest );
304 311
 	iob_unput ( iobuf, ( iob_len ( iobuf ) - ulen ) );
305 312
 	iob_pull ( iobuf, sizeof ( *udphdr ) );
306 313
 

Laddar…
Avbryt
Spara