Browse Source

[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 years ago
parent
commit
aa160211c2
2 changed files with 38 additions and 22 deletions
  1. 9
    0
      src/include/gpxe/in.h
  2. 29
    22
      src/net/udp.c

+ 9
- 0
src/include/gpxe/in.h View File

62
 	uint16_t sin_port;
62
 	uint16_t sin_port;
63
 	/** IPv4 address */
63
 	/** IPv4 address */
64
 	struct in_addr sin_addr;
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 View File

29
 	/** Data transfer interface */
29
 	/** Data transfer interface */
30
 	struct xfer_interface xfer;
30
 	struct xfer_interface xfer;
31
 
31
 
32
+	/** Local socket address */
33
+	struct sockaddr_tcpip local;
32
 	/** Remote socket address */
34
 	/** Remote socket address */
33
 	struct sockaddr_tcpip peer;
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
  * Bind UDP connection to local port
48
  * Bind UDP connection to local port
49
  *
49
  *
50
  * @v udp		UDP connection
50
  * @v udp		UDP connection
51
- * @v port		Local port, in network byte order, or zero
52
  * @ret rc		Return status code
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
 	struct udp_connection *existing;
57
 	struct udp_connection *existing;
59
 	static uint16_t try_port = 1024;
58
 	static uint16_t try_port = 1024;
60
 
59
 
61
 	/* If no port specified, find the first available port */
60
 	/* If no port specified, find the first available port */
62
-	if ( ! port ) {
61
+	if ( ! udp->local.st_port ) {
63
 		for ( ; try_port ; try_port++ ) {
62
 		for ( ; try_port ; try_port++ ) {
64
 			if ( try_port < 1024 )
63
 			if ( try_port < 1024 )
65
 				continue;
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
 				return 0;
67
 				return 0;
68
 		}
68
 		}
69
 		return -EADDRINUSE;
69
 		return -EADDRINUSE;
71
 
71
 
72
 	/* Attempt bind to local port */
72
 	/* Attempt bind to local port */
73
 	list_for_each_entry ( existing, &udp_conns, list ) {
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
 			DBGC ( udp, "UDP %p could not bind: port %d in use\n",
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
 			return -EADDRINUSE;
77
 			return -EADDRINUSE;
78
 		}
78
 		}
79
 	}
79
 	}
80
-	udp->local_port = port;
81
 
80
 
82
 	/* Add to UDP connection list */
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
 	return 0;
85
 	return 0;
86
 }
86
 }
100
 	struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
100
 	struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
101
 	struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
101
 	struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
102
 	struct udp_connection *udp;
102
 	struct udp_connection *udp;
103
-	unsigned int bind_port;
104
 	int rc;
103
 	int rc;
105
 
104
 
106
 	/* Allocate and initialise structure */
105
 	/* Allocate and initialise structure */
111
 	xfer_init ( &udp->xfer, &udp_xfer_operations, &udp->refcnt );
110
 	xfer_init ( &udp->xfer, &udp_xfer_operations, &udp->refcnt );
112
 	if ( st_peer )
111
 	if ( st_peer )
113
 		memcpy ( &udp->peer, st_peer, sizeof ( udp->peer ) );
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
 	/* Bind to local port */
116
 	/* Bind to local port */
116
 	if ( ! promisc ) {
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
 			goto err;
119
 			goto err;
120
 	}
120
 	}
121
 
121
 
201
 
201
 
202
 	/* Fill in default values if not explicitly provided */
202
 	/* Fill in default values if not explicitly provided */
203
 	if ( ! src_port )
203
 	if ( ! src_port )
204
-		src_port = udp->local_port;
204
+		src_port = udp->local.st_port;
205
 	if ( ! dest )
205
 	if ( ! dest )
206
 		dest = &udp->peer;
206
 		dest = &udp->peer;
207
 
207
 
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
  * @ret udp		UDP connection, or NULL
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
 	struct udp_connection *udp;
241
 	struct udp_connection *udp;
241
 
242
 
242
 	list_for_each_entry ( udp, &udp_conns, list ) {
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
 			return udp;
252
 			return udp;
246
 		}
253
 		}
247
 	}
254
 	}
300
 	/* Parse parameters from header and strip header */
307
 	/* Parse parameters from header and strip header */
301
 	st_src->st_port = udphdr->src;
308
 	st_src->st_port = udphdr->src;
302
 	st_dest->st_port = udphdr->dest;
309
 	st_dest->st_port = udphdr->dest;
303
-	udp = udp_demux ( udphdr->dest );
310
+	udp = udp_demux ( st_dest );
304
 	iob_unput ( iobuf, ( iob_len ( iobuf ) - ulen ) );
311
 	iob_unput ( iobuf, ( iob_len ( iobuf ) - ulen ) );
305
 	iob_pull ( iobuf, sizeof ( *udphdr ) );
312
 	iob_pull ( iobuf, sizeof ( *udphdr ) );
306
 
313
 

Loading…
Cancel
Save