1 /* @(#) interface/address conversion
3 * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com)
5 * This file is part of udpxy.
7 * udpxy is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * udpxy is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with udpxy. If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/socket.h>
23 #include <sys/ioctl.h>
24 #include <sys/types.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
40 /* check if ifr contains info on the desired ifname
43 chkifr( const struct ifreq
* ifr
, const char* ifname
,
44 const size_t addrlen
, size_t* offset
)
48 assert(ifr
&& ifname
&& offset
);
50 #ifdef NO_SOCKADDR_SA_LEN
51 switch( ifr
->ifr_addr
.sa_family
)
53 #ifndef NO_INET6_SUPPORT
54 case AF_INET6
: sa_len
= sizeof(struct sockaddr_in6
); break;
56 case AF_INET
: sa_len
= sizeof(struct sockaddr
); break;
57 default: sa_len
= 0; break;
60 sa_len
= ifr
->ifr_addr
.sa_len
;
64 if ( (ifr
->ifr_addr
.sa_family
== AF_INET
) &&
65 (0 == strncmp(ifname
, ifr
->ifr_name
, sizeof(struct ifreq
))) &&
66 (addrlen
>= sa_len
) ) {
73 *offset
= sizeof(*ifr
);
75 *offset
= (sa_len
+ sizeof( ifr
->ifr_name
));
76 /* the above is per R. Stevens' book and not working on 64-bit Linux */
84 /* retrieve IPv4 address of the given network interface
87 if2addr( const char* ifname
,
88 struct sockaddr
*addr
, size_t addrlen
)
92 size_t buflen
, offset
;
97 static size_t IFC_TABLE_SIZE
;
99 static const size_t IFC_ENTRIES
= 32;
100 static const size_t MAX_IFCBUF_SIZE
= (1024 * 256);
102 IFC_TABLE_SIZE
= sizeof(struct ifreq
) * IFC_ENTRIES
;
104 assert( ifname
&& addr
&& addrlen
);
107 /* acquire the list of network interfaces */
109 sockfd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
110 if( -1 == sockfd
) return -1;
112 buf
= NULL
; buflen
= IFC_TABLE_SIZE
; last_len
= 0;
113 for( ; buflen
< MAX_IFCBUF_SIZE
; buflen
+= IFC_TABLE_SIZE
) {
114 if( NULL
== (buf
= malloc( buflen
)) ) {
119 ifc
.ifc_len
= buflen
;
121 if( ioctl( sockfd
, SIOCGIFCONF
, &ifc
) < 0 ) {
122 if( (EINVAL
!= errno
) || (last_len
!= 0) ) {
128 if( ifc
.ifc_len
== last_len
)
131 last_len
= ifc
.ifc_len
;
138 (void) close( sockfd
);
139 if( buflen
> MAX_IFCBUF_SIZE
) rc
= -1;
142 if( NULL
!= buf
) free( buf
);
146 assert( ifc
.ifc_buf
);
148 /* look for ifname in the list */
150 for( rec
= ifc
.ifc_buf
; rec
< (ifc
.ifc_buf
+ ifc
.ifc_len
); ) {
151 (void) memcpy( &ifr
, rec
, sizeof(struct ifreq
) );
154 rc
= chkifr( &ifr
, ifname
, addrlen
, &offset
);
156 (void) memcpy( addr
, &(ifr
.ifr_addr
), offset
);
160 if( 0 == offset
) break;
164 if( rec
>= (buf
+ ifc
.ifc_len
) ) {
173 /* convert input parameter into an IPv4-address string
176 get_ipv4_address( const char* s
, char* buf
, size_t len
)
178 struct sockaddr_in saddr
;
181 assert( s
&& buf
&& len
);
183 if( 1 == inet_aton(s
, &(saddr
.sin_addr
)) ) {
184 (void) strncpy( buf
, s
, len
);
187 rc
= if2addr( s
, (struct sockaddr
*)&saddr
, sizeof(saddr
) );
188 if( 0 != rc
) return rc
;
190 (void) strncpy( buf
, inet_ntoa(saddr
.sin_addr
), len
);
198 /* split input string into IP address and port
201 get_addrport( const char* s
, char* addr
, size_t len
, int* port
)
203 struct sockaddr_in saddr
;
207 static const int ERR_NOPORT
= -1;
208 static const int ERR_BADADDR
= -2;
209 static const int ERR_BADPORT
= -3;
210 static const int ERR_OVERFLOW
= -4;
212 assert( s
&& addr
&& len
&& port
);
214 for( i
= 0; (i
< len
) && s
[i
] && (':' != s
[i
]); ++i
)
221 /* IP address is not followed by port */
222 if( ':' != s
[ i
] ) return ERR_NOPORT
;
224 if( 1 != inet_aton( addr
, &(saddr
.sin_addr
)) )
228 if( i
>= len
|| !s
[i
] ) return ERR_NOPORT
;
231 iport
= atoi( s
+ i
);
232 if( errno
|| (iport
<= 0) || (iport
> (int)USHRT_MAX
) )