aboutsummaryrefslogtreecommitdiffstats
path: root/tools/libxutil/sys_net.c
blob: 0e7ac5d6389c955eb3f35527d98217974103734b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
/*
 * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of the
 * License, or  (at your option) any later version. This library is 
 * distributed in the  hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */

#include "sys_net.h"
#include "sys_string.h"

/** @file
 * All network data are kept in network order and only converted to
 * host order for display. Network data includes IP addresses, port numbers and
 * network masks.
 */

/** Maximum value for a port. */
#define PORT_MAX 0xffff

/** Convert a number of bits to a network mask
 * for IP addresses. The number of bits must
 * be in the range 1-31.
 *
 * @param n number of bits to set in the mask
 * @return value with n high bits set (in network order)
 */
unsigned long bits_to_mask(int n){
    unsigned long mask = (n ? (1 << 31) : 0);
    int i;
    for(i=1; i<n; i++){
        mask |= (mask >> 1);
    }
    return htonl(mask);
}

/** Convert a network mask to a number of bits.
 *
 * @param mask network mask in network order
 * @return number of bits in mask
 */
int mask_to_bits(unsigned long mask){
    // Start with n set to the number of bits in the mask. Then reduce n by
    // the number of low zero bits in the mask.
    int n = 32;
    for(mask = ntohl(mask);
        (mask & 1)==0 && n>0;
        mask >>= 1){
        n--;
    }
    return n;
}

/** Get the index of the first occurrence of a character in a string.
 * Stops at end of string or after n characters.
 *
 * @param s input string
 * @param n maximum number of charactes to search
 * @param c character to look for
 * @return index of first occurrence, -1 if not found
 */
inline static int indexof(const char *s, int n, char c){
    int i;
    for(i=0; i<n && *s; i++, s++){
        if(*s == c) return i;
    }
    return -1;
}

/** Convert an IPv4 address in dot notation into an unsigned long (in network order).
 *
 * @param s input string
 * @param address where to put the address
 * @return 0 on success, -1 on error
 */
int get_inet_addr(const char *s, unsigned long *address){
    // Number of bits in a byte.
    const int BYTE_BITS = 8;
    // Number of bytes in a word.
    const int WORD_BYTES = 4;
    // Max value for a component of an address.
    const int ADDR_MAX  = 255;
    // Separator for components of an address.
    const char dot = '.';

    int n;
    unsigned long addr = 0;
    unsigned long v;
    int i;
    int err = -1;
    // Bit shift for the current byte.
    int shift = BYTE_BITS * (WORD_BYTES - 1);
    char buf[64];

    n = strlen(s);
    if(n >= sizeof(buf)){
        goto exit;
    }
    for(i=0; i < WORD_BYTES; i++){
        int idx = indexof(s, n, dot);
        idx = (idx < 0 ? strlen(s) : idx);
        strncpy(buf, s, idx); buf[idx]='\0';
        if(convert_atoul(buf, &v)){
            goto exit;
        }
        if(v < 0 || v > ADDR_MAX){
            goto exit;
        }
        addr |= (v << shift);
        if(idx == n) break;
        shift -= BYTE_BITS;
        s += idx+1;
    }
    err = 0;
  exit:
    addr = htonl(addr);
    *address = (err ? 0 : addr);
    return err;
}

#ifdef __KERNEL__
/** Convert an address in network order to IPv4 dot notation.
 * The return value is a static buffer which is overwritten on each call.
 *
 * @param inaddr address (in network order)
 * @return address in dot notation
 */
char *inet_ntoa(struct in_addr inaddr){
    static char address[16] = {};
    uint32_t addr = ntohl(inaddr.s_addr);
    snprintf(address, sizeof(address), "%d.%d.%d.%d",
            (unsigned)((addr >> 24) & 0xff),
            (unsigned)((addr >> 16) & 0xff),
            (unsigned)((addr >>  8) & 0xff),
            (unsigned)((addr      ) & 0xff));
    return address;
}


/** Convert a string in IPv4 dot notation to an int in network order.
 *
 * @param address address in dot notation
 * @param inp result of conversion (in network order)
 * @return 0 on success, error code on error
 */
int inet_aton(const char *address, struct in_addr *inp){
    int err = 0; 
    unsigned long addr;
    
    err = get_inet_addr(address, &addr);
    if(err) goto exit;
    inp->s_addr = addr;
  exit:
    return err;
}
#endif

/** Convert a hostname or IPv4 address string to an address in network order.
 *
 * @param name input hostname or address string
 * @param address where to put the address
 * @return 1 if address found OK, 0 otherwise
 */
int get_host_address(const char *name, unsigned long *address){
#ifdef __KERNEL__
    return get_inet_addr(name, address) == 0;
#else
    struct hostent *host = gethostbyname(name);
    if(!host){
        return 0;
    }
    *address = ((struct in_addr *)(host->h_addr))->s_addr;
    return 1;
#endif
}

/** Convert a service name to a port (in network order).
 *
 * @param name service name
 * @param port where to put the port
 * @return 1 if service port found OK, 0 otherwise
 */
int get_service_port(const char *name, unsigned long *port){
#ifdef __KERNEL__
    return 0;
#else
    struct servent *service;
    service = getservbyname(name, 0);
    if(!service){
        return 0;
    }
    *port = service->s_port;
    return 1;
#endif
}

/** Convert a port number (in network order) to a service name.
 *
 * @param port the port number
 * @return service name if found OK, 0 otherwise
 */
char *get_port_service(unsigned long port){
#ifdef __KERNEL__
    return 0;
#else
    struct servent *service = getservbyport(port, 0);
    return (service ? service->s_name : 0);
#endif
}

/** Convert a decimal integer or service name to a port (in network order).
 *
 * @param s input to convert
 * @param port where to put the port
 * @return 1 if port found OK, 0 otherwise
 */
int convert_service_to_port(const char *s, unsigned long *port){
    int ok = 0;
    unsigned long value;
    if(convert_atoul(s, &value)){
        ok = get_service_port(s, &value);
    } else {
        ok = (0 <= value) && (value <= PORT_MAX);
        value = htons((unsigned short)value);
    }
    *port = (ok ? value : 0);
    return ok;
}

#define MAC_ELEMENT_N  6 // Number of elements in a MAC address.
#define MAC_DIGIT_N    2 // Number of digits in an element in a MAC address.
#define MAC_LENGTH    17 //((MAC_ELEMENT_N * MAC_DIGIT_N) + MAC_ELEMENT_N - 1)

/** Convert a mac address from a string of the form
 * XX:XX:XX:XX:XX:XX to numerical form (an array of 6 unsigned chars).
 * Each X denotes a hex digit: 0..9, a..f, A..F.
 * Also supports using '-' as the separator instead of ':'.
 *
 * @param mac_in string to convert
 * @param mac destination for the value
 * @return 0 on success, -1 on error
 */
int mac_aton(const char *mac_in, unsigned char *mac){
    int err = 0;
    int i, j;
    const char *p;
    char sep = 0;
    unsigned char d;
    if(!mac_in || strlen(mac_in) != MAC_LENGTH){
        err = -1;
        goto exit;
    }
    for(i = 0, p = mac_in; i < MAC_ELEMENT_N; i++){
        d = 0;
        if(i){
            if(!sep){
                if(*p == ':' || *p == '-') sep = *p;
            }
            if(sep && *p == sep){
                p++;
            } else {
                err = -1;
                goto exit;
            }
        }
        for(j = 0; j < MAC_DIGIT_N; j++, p++){
            if(j) d <<= 4;
            if(*p >= '0' && *p <= '9'){
                d += (*p - '0');
            } else if(*p >= 'A' && *p <= 'F'){
                d += (*p - 'A') + 10;
            } else if(*p >= 'a' && *p <= 'f'){
                d += (*p - 'a') + 10;
            } else {
                err = -1;
                goto exit;
            }
        }
        mac[i] = d;
    }
  exit:
    return err;
}

/** Convert a MAC address from numerical form to a string.
 *
 * @param mac address to convert
 * @return static string value
 */
char *mac_ntoa(const unsigned char *mac){
    static char buf[MAC_LENGTH + 1];
    int buf_n = sizeof(buf);

    memset(buf, buf_n, 0);
    snprintf(buf, buf_n, "%02x:%02x:%02x:%02x:%02x:%02x",
             mac[0], mac[1], mac[2],
             mac[3], mac[4], mac[5]);
    buf[buf_n - 1] = '\0';
    return buf;
}