2 * Re-map bind() on 0.0.0.0 or :: to bind() on the node's public IP address
3 * Jude Nelson (jcnelson@cs.princeton.edu)
10 #include <sys/socket.h>
17 int (*bind_original)(int fd, struct sockaddr* addr, socklen_t len ) = NULL;
19 // which C library do we need to replace bind in?
20 #if defined(__LP64__) || defined(_LP64)
21 #define LIBC_PATH "/lib64/libc.so.6"
23 #define LIBC_PATH "/lib/libc.so.6"
26 // get the node's public IP address
27 static int get_public_ip( struct sockaddr* addr ) {
29 struct addrinfo hints;
30 memset( &hints, 0, sizeof(hints) );
31 hints.ai_family = addr->sa_family;
32 hints.ai_flags = AI_CANONNAME;
33 hints.ai_protocol = 0;
34 hints.ai_canonname = NULL;
40 // get the node hostname
41 struct addrinfo *result = NULL;
42 char hostname[HOST_NAME_MAX+1];
43 gethostname( hostname, HOST_NAME_MAX );
45 // get the address information from the hostname
46 rc = getaddrinfo( hostname, NULL, &hints, &result );
48 // could not get addr info
49 fprintf(stderr, "bind_public: get_public_ip: getaddrinfo: %s\n", gai_strerror( rc ) );
54 // NOTE: there should only be one IP address for this node, but it
55 // is possible that it can have more. Here, we just take the first
58 switch( addr->sa_family ) {
61 ((struct sockaddr_in*)addr)->sin_addr = ((struct sockaddr_in*)result->ai_addr)->sin_addr;
66 ((struct sockaddr_in6*)addr)->sin6_addr = ((struct sockaddr_in6*)result->ai_addr)->sin6_addr;
70 fprintf(stderr, "bind_public: get_public_ip: unknown socket address family %d\n", addr->sa_family );
75 freeaddrinfo( result );
81 // is a particular sockaddr initialized to 0.0.0.0 or ::?
82 static int is_addr_any( const struct sockaddr* addr ) {
85 switch( addr->sa_family ) {
88 struct sockaddr_in* addr4 = (struct sockaddr_in*)addr;
89 if( addr4->sin_addr.s_addr == INADDR_ANY )
90 ret = 1; // this is 0.0.0.0
95 struct sockaddr_in6* addr6 = (struct sockaddr_in6*)addr;
96 if( memcmp( &addr6->sin6_addr, &in6addr_any, sizeof(in6addr_any) ) == 0 )
97 ret = 1; // this is ::
102 fprintf(stderr, "bind_public: is_addr_any: unsupported socket address family %d\n", addr->sa_family );
111 // copy over non-IP-related fields from one address to another
112 static int copy_nonIP_fields( struct sockaddr* dest, const struct sockaddr* src ) {
115 switch( src->sa_family ) {
118 struct sockaddr_in* dest4 = (struct sockaddr_in*)dest;
119 struct sockaddr_in* src4 = (struct sockaddr_in*)src;
121 dest4->sin_family = src4->sin_family;
122 dest4->sin_port = src4->sin_port;
127 struct sockaddr_in6* dest6 = (struct sockaddr_in6*)dest;
128 struct sockaddr_in6* src6 = (struct sockaddr_in6*)src;
130 dest6->sin6_family = src6->sin6_family;
131 dest6->sin6_port = src6->sin6_port;
132 dest6->sin6_flowinfo = src6->sin6_flowinfo;
133 dest6->sin6_scope_id = src6->sin6_scope_id;
138 fprintf(stderr, "bind_public: copy_nonIP_fields: unsupported socket address family %d\n", src->sa_family );
147 static void print_ip4( uint32_t i ) {
149 printf("%i.%i.%i.%i",
156 static void print_ip6( uint8_t* bytes ) {
157 printf("%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x",
158 bytes[15], bytes[14], bytes[13], bytes[12],
159 bytes[11], bytes[10], bytes[9], bytes[8],
160 bytes[7], bytes[6], bytes[5], bytes[4],
161 bytes[3], bytes[2], bytes[1], bytes[0] );
164 static void debug( const struct sockaddr* before, struct sockaddr* after ) {
165 printf("bind_public: ");
166 switch( before->sa_family ) {
168 print_ip4( ((struct sockaddr_in*)before)->sin_addr.s_addr );
170 print_ip4( ((struct sockaddr_in*)after)->sin_addr.s_addr );
174 print_ip6( ((struct sockaddr_in6*)before)->sin6_addr.s6_addr );
176 print_ip6( ((struct sockaddr_in6*)after)->sin6_addr.s6_addr );
180 printf("UNKNOWN --> UNKNOWN\n");
186 // if the caller attempted to bind to 0.0.0.0 or ::, then change it to
187 // this node's public IP address
188 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
190 // save the original bind() call
191 void *handle = dlopen( LIBC_PATH, RTLD_LAZY );
193 fprintf( stderr, "Error loading libc.so.6\n" );
197 bind_original = dlsym(handle, "bind");
198 if( bind_original == NULL ) {
199 fprintf( stderr, "Error loading socket symbol\n" );
204 int rc = is_addr_any( addr );
207 // rewrite this address
208 struct sockaddr_storage new_addr;
209 memset( &new_addr, 0, sizeof(struct sockaddr_storage));
211 if( copy_nonIP_fields( (struct sockaddr*)&new_addr, addr ) != 0 ) {
215 else if( get_public_ip( (struct sockaddr*)&new_addr ) != 0 ) {
219 // Un-comment the following line to activate the debug message
220 //debug( addr, (struct sockaddr*)&new_addr );
221 rc = bind_original( sockfd, (struct sockaddr*)&new_addr, addrlen );
225 return bind_original( sockfd, addr, addrlen );