File: addr.c

package info (click to toggle)
tcng 10b-1
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 3,632 kB
  • ctags: 2,515
  • sloc: ansic: 19,038; pascal: 4,640; yacc: 2,619; sh: 1,908; perl: 1,546; lex: 772; makefile: 755
file content (111 lines) | stat: -rw-r--r-- 2,770 bytes parent folder | download | duplicates (5)
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
/*
 * addr.c - Address conversion
 *
 * Written 2002 by Werner Almesberger
 * Copyright 2002 Bivio Networks, Werner Almesberger
 */


#include <stdint.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>

#include "memutil.h"

#include "u128.h"
#include "addr.h"


extern void addr_error_hook(const char *msg);


/* ----- Cache management -------------------------------------------------- */


static struct cache_entry {
    const char *name;
    U128 value;
    struct cache_entry *next;
} *ipv4_cache = NULL,*ipv6_cache = NULL;


static const struct cache_entry *cache_lookup(const struct cache_entry *root,
  const char *name)
{
    while (root && strcmp(root->name,name)) root = root->next;
    return root;
}


static void cache_add(struct cache_entry **root,const char *name,U128 value)
{
    struct cache_entry *new = alloc_t(struct cache_entry);

    new->name = stralloc(name);
    new->value = value;
    new->next = *root;
    *root = new;
}


/* ----- Lookup functions -------------------------------------------------- */


uint32_t ipv4_host(const char *name,int allow_dns)
{
    struct addrinfo hints,*res;
    uint32_t r;
    int error;

    if (allow_dns) {
	const struct cache_entry *entry;

	entry = cache_lookup(ipv4_cache,name);
	if (entry) return u128_to_32(entry->value);
    }
    memset(&hints,0,sizeof(hints));
    hints.ai_flags = allow_dns ? 0 : AI_NUMERICHOST;
    hints.ai_family = PF_INET;
    hints.ai_socktype = 0;
    hints.ai_protocol = 0;
    error = getaddrinfo(name,NULL,&hints,&res);
    if (error) addr_error_hook(gai_strerror(error));
    r = ntohl(((struct sockaddr_in *) res->ai_addr)->sin_addr.s_addr);
    freeaddrinfo(res);
    if (allow_dns) cache_add(&ipv4_cache,name,u128_from_32(r));
    return r;
}


U128 ipv6_host(const char *name,int allow_dns)
{
    struct addrinfo hints,*res;
    unsigned char *a;
    U128 r;
    int error;

    if (allow_dns) {
	const struct cache_entry *entry;

	entry = cache_lookup(ipv6_cache,name);
	if (entry) return entry->value;
    }
    memset(&hints,0,sizeof(hints));
    hints.ai_flags = allow_dns ? 0 : AI_NUMERICHOST;
    hints.ai_family = PF_INET6;
    hints.ai_socktype = 0;
    hints.ai_protocol = 0;
    error = getaddrinfo(name,NULL,&hints,&res);
    if (error) addr_error_hook(gai_strerror(error));
    a = ((struct sockaddr_in6 *) res->ai_addr)->sin6_addr.s6_addr;
    r.v[3] = (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
    r.v[2] = (a[4] << 24) | (a[5] << 16) | (a[6] << 8) | a[7];
    r.v[1] = (a[8] << 24) | (a[9] << 16) | (a[10] << 8) | a[11];
    r.v[0] = (a[12] << 24) | (a[13] << 16) | (a[14] << 8) | a[15];
    freeaddrinfo(res);
    if (allow_dns) cache_add(&ipv6_cache,name,r);
    return r;
}