summaryrefslogtreecommitdiff
path: root/lookup.c
blob: 30d6da9e8d48bf7a796a620786dd4c29a280fbf2 (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
/*
 * netsniff-ng - the packet sniffing beast
 * Copyright 2009, 2010 Daniel Borkmann.
 * Copyright 2014, 2015 Tobias Klauser
 * Subject to the GPL, version 2.
 */

#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

#include "hash.h"
#include "str.h"
#include "lookup.h"
#include "xmalloc.h"

static bool lookup_initialized[LT_MAX];
static struct hash_table lookup_tables[LT_MAX];
static const char * const lookup_files[] = {
	[LT_PORTS_UDP]	= ETCDIRE_STRING "/udp.conf",
	[LT_PORTS_TCP]	= ETCDIRE_STRING "/tcp.conf",
	[LT_ETHERTYPES]	= ETCDIRE_STRING "/ether.conf",
};

struct lookup_entry {
	unsigned int id;
	char *str;
	struct lookup_entry *next;
};

void lookup_init(enum lookup_type which)
{
	FILE *fp;
	char buff[128], *ptr, *end;
	const char *file;
	struct hash_table *table;
	struct lookup_entry *p;
	void **pos;

	bug_on(which >= LT_MAX);
	if (lookup_initialized[which])
		return;
	table = &lookup_tables[which];
	file = lookup_files[which];

	fp = fopen(file, "r");
	if (!fp) {
		fprintf(stderr, "Cannot open %s: %s."
				"Port name resolution won't be available.\n",
				file, strerror(errno));
		return;
	}

	memset(buff, 0, sizeof(buff));

	while (fgets(buff, sizeof(buff), fp) != NULL) {
		buff[sizeof(buff) - 1] = 0;
		ptr = buff;

		p = xmalloc(sizeof(*p));
		p->id = strtol(ptr, &end, 0);
		/* not a valid line, skip */
		if (p->id == 0 && end == ptr) {
			xfree(p);
			continue;
		}

		ptr = strstr(buff, ", ");
		/* likewise */
		if (!ptr) {
			xfree(p);
			continue;
		}

		ptr += strlen(", ");
		ptr = strtrim_right(ptr, '\n');
		ptr = strtrim_right(ptr, ' ');

		p->str = xstrdup(ptr);
		p->next = NULL;

		pos = insert_hash(p->id, p, table);
		if (pos) {
			p->next = *pos;
			*pos = p;
		}

		memset(buff, 0, sizeof(buff));
	}

	fclose(fp);
	lookup_initialized[which] = true;
}

static int __lookup_cleanup_single(void *ptr)
{
	struct lookup_entry *tmp, *p = ptr;

	if (!ptr)
		return 0;

	while ((tmp = p->next)) {
		xfree(p->str);
		xfree(p);
		p = tmp;
	}

	xfree(p->str);
	xfree(p);

	return 0;
}

void lookup_cleanup(enum lookup_type which)
{
	struct hash_table *table;

	bug_on(which >= LT_MAX);
	if (!lookup_initialized[which])
		return;
	table = &lookup_tables[which];

	for_each_hash(table, __lookup_cleanup_single);
	free_hash(table);
	lookup_initialized[which] = false;
}

#define __do_lookup_inline(id, hash_ptr)	\
	({								\
		struct lookup_entry *entry = lookup_hash(id, hash_ptr);	\
									\
		while (entry && id != entry->id)			\
			entry = entry->next;				\
									\
		(entry && id == entry->id ? entry->str : NULL); \
	})

char *lookup_ether_type(unsigned int id)
{
	return __do_lookup_inline(id, &lookup_tables[LT_ETHERTYPES]);
}

char *lookup_port_udp(unsigned int id)
{
	return __do_lookup_inline(id, &lookup_tables[LT_PORTS_UDP]);
}

char *lookup_port_tcp(unsigned int id)
{
	return __do_lookup_inline(id, &lookup_tables[LT_PORTS_TCP]);
}