~ubuntu-branches/ubuntu/trusty/libdumbnet/trusty

« back to all changes in this revision

Viewing changes to src/route-linux.c

  • Committer: Bazaar Package Importer
  • Author(s): Simon Law
  • Date: 2003-11-13 01:44:56 UTC
  • Revision ID: james.westby@ubuntu.com-20031113014456-6bbmmk2g5clgz71s
Tags: upstream-1.7
ImportĀ upstreamĀ versionĀ 1.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * route-linux.c
 
3
 *
 
4
 * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
 
5
 *
 
6
 * $Id: route-linux.c,v 1.12 2002/02/08 07:41:04 dugsong Exp $
 
7
 */
 
8
 
 
9
#include "config.h"
 
10
 
 
11
#include <sys/types.h>
 
12
#include <sys/ioctl.h>
 
13
#include <sys/socket.h>
 
14
#include <sys/uio.h>
 
15
 
 
16
#include <asm/types.h>
 
17
#include <linux/netlink.h>
 
18
#include <linux/rtnetlink.h>
 
19
 
 
20
#include <net/route.h>
 
21
 
 
22
#include <ctype.h>
 
23
#include <errno.h>
 
24
#include <stdio.h>
 
25
#include <stdlib.h>
 
26
#include <string.h>
 
27
#include <unistd.h>
 
28
 
 
29
#include "dnet.h"
 
30
 
 
31
#define PROC_ROUTE_FILE "/proc/net/route"
 
32
 
 
33
struct route_handle {
 
34
        int      fd;
 
35
        int      nlfd;
 
36
};
 
37
 
 
38
route_t *
 
39
route_open(void)
 
40
{
 
41
        struct sockaddr_nl snl;
 
42
        route_t *r;
 
43
 
 
44
        if ((r = calloc(1, sizeof(*r))) == NULL)
 
45
                return (NULL);
 
46
 
 
47
        if ((r->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
 
48
                return (route_close(r));
 
49
        
 
50
        if ((r->nlfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0)
 
51
                return (route_close(r));
 
52
        
 
53
        memset(&snl, 0, sizeof(snl));
 
54
        snl.nl_family = AF_NETLINK;
 
55
 
 
56
        if (bind(r->nlfd, (struct sockaddr *)&snl, sizeof(snl)) < 0)
 
57
                return (route_close(r));
 
58
        
 
59
        return (r);
 
60
}
 
61
 
 
62
int
 
63
route_add(route_t *r, const struct route_entry *entry)
 
64
{
 
65
        struct rtentry rt;
 
66
 
 
67
        memset(&rt, 0, sizeof(rt));
 
68
 
 
69
        if (addr_ntos(&entry->route_dst, &rt.rt_dst) < 0 ||
 
70
            addr_ntos(&entry->route_gw, &rt.rt_gateway) < 0)
 
71
                return (-1);
 
72
 
 
73
        if (entry->route_dst.addr_bits < IP_ADDR_BITS) {
 
74
                rt.rt_flags = RTF_UP | RTF_GATEWAY;
 
75
                if (addr_btos(entry->route_dst.addr_bits, &rt.rt_genmask) < 0)
 
76
                        return (-1);
 
77
        } else {
 
78
                rt.rt_flags = RTF_UP | RTF_HOST | RTF_GATEWAY;
 
79
                addr_btos(IP_ADDR_BITS, &rt.rt_genmask);
 
80
        }
 
81
        return (ioctl(r->fd, SIOCADDRT, &rt));
 
82
}
 
83
 
 
84
int
 
85
route_delete(route_t *r, const struct route_entry *entry)
 
86
{
 
87
        struct rtentry rt;
 
88
 
 
89
        memset(&rt, 0, sizeof(rt));
 
90
 
 
91
        if (addr_ntos(&entry->route_dst, &rt.rt_dst) < 0)
 
92
                return (-1);
 
93
 
 
94
        if (entry->route_dst.addr_bits < IP_ADDR_BITS) {
 
95
                rt.rt_flags = RTF_UP;
 
96
                if (addr_btos(entry->route_dst.addr_bits, &rt.rt_genmask) < 0)
 
97
                        return (-1);
 
98
        } else {
 
99
                rt.rt_flags = RTF_UP | RTF_HOST;
 
100
                addr_btos(IP_ADDR_BITS, &rt.rt_genmask);
 
101
        }
 
102
        return (ioctl(r->fd, SIOCDELRT, &rt));
 
103
}
 
104
 
 
105
int
 
106
route_get(route_t *r, struct route_entry *entry)
 
107
{
 
108
        static int seq;
 
109
        struct nlmsghdr *nmsg;
 
110
        struct rtmsg *rmsg;
 
111
        struct rtattr *rta;
 
112
        struct sockaddr_nl snl;
 
113
        struct iovec iov;
 
114
        struct msghdr msg;
 
115
        u_char buf[512];
 
116
        int i;
 
117
 
 
118
        if (entry->route_dst.addr_type != ADDR_TYPE_IP) {
 
119
                errno = EINVAL;
 
120
                return (-1);
 
121
        }
 
122
        memset(buf, 0, sizeof(buf));
 
123
 
 
124
        nmsg = (struct nlmsghdr *)buf;
 
125
        nmsg->nlmsg_len = NLMSG_LENGTH(sizeof(*nmsg)) +
 
126
            RTA_LENGTH(IP_ADDR_LEN);
 
127
        nmsg->nlmsg_flags = NLM_F_REQUEST;
 
128
        nmsg->nlmsg_type = RTM_GETROUTE;
 
129
        nmsg->nlmsg_seq = ++seq;
 
130
 
 
131
        rmsg = (struct rtmsg *)(nmsg + 1);
 
132
        rmsg->rtm_family = AF_INET;
 
133
        rmsg->rtm_dst_len = entry->route_dst.addr_bits;
 
134
        
 
135
        rta = RTM_RTA(rmsg);
 
136
        rta->rta_type = RTA_DST;
 
137
        rta->rta_len = RTA_LENGTH(IP_ADDR_LEN);
 
138
 
 
139
        /* XXX - gross hack for default route */
 
140
        if (entry->route_dst.addr_ip == IP_ADDR_ANY) {
 
141
                i = htonl(0x60060606);
 
142
                memcpy(RTA_DATA(rta), &i, IP_ADDR_LEN);
 
143
        } else
 
144
                memcpy(RTA_DATA(rta), &entry->route_dst.addr_ip, IP_ADDR_LEN);
 
145
        
 
146
        memset(&snl, 0, sizeof(snl));
 
147
        snl.nl_family = AF_NETLINK;
 
148
 
 
149
        iov.iov_base = nmsg;
 
150
        iov.iov_len = nmsg->nlmsg_len;
 
151
        
 
152
        memset(&msg, 0, sizeof(msg));
 
153
        msg.msg_name = &snl;
 
154
        msg.msg_namelen = sizeof(snl);
 
155
        msg.msg_iov = &iov;
 
156
        msg.msg_iovlen = 1;
 
157
        
 
158
        if (sendmsg(r->nlfd, &msg, 0) < 0)
 
159
                return (-1);
 
160
 
 
161
        iov.iov_base = buf;
 
162
        iov.iov_len = sizeof(buf);
 
163
        
 
164
        if ((i = recvmsg(r->nlfd, &msg, 0)) <= 0)
 
165
                return (-1);
 
166
 
 
167
        if (nmsg->nlmsg_len < sizeof(*nmsg) || nmsg->nlmsg_len > i ||
 
168
            nmsg->nlmsg_seq != seq) {
 
169
                errno = EINVAL;
 
170
                return (-1);
 
171
        }
 
172
        if (nmsg->nlmsg_type == NLMSG_ERROR)
 
173
                return (-1);
 
174
        
 
175
        i -= NLMSG_LENGTH(sizeof(*nmsg));
 
176
        
 
177
        while (RTA_OK(rta, i)) {
 
178
                if (rta->rta_type == RTA_GATEWAY) {
 
179
                        entry->route_gw.addr_type = ADDR_TYPE_IP;
 
180
                        memcpy(&entry->route_gw.addr_ip,
 
181
                            RTA_DATA(rta), IP_ADDR_LEN);
 
182
                        entry->route_gw.addr_bits = IP_ADDR_BITS;
 
183
                        return (0);
 
184
                }
 
185
                rta = RTA_NEXT(rta, i);
 
186
        }
 
187
        errno = ESRCH;
 
188
        
 
189
        return (-1);
 
190
}
 
191
 
 
192
int
 
193
route_loop(route_t *r, route_handler callback, void *arg)
 
194
{
 
195
        FILE *fp;
 
196
        char buf[BUFSIZ], ifbuf[16];
 
197
        int i, iflags, refcnt, use, metric, mss, win, irtt, ret;
 
198
        struct route_entry entry;
 
199
        uint32_t mask;
 
200
 
 
201
        entry.route_dst.addr_type = entry.route_gw.addr_type = ADDR_TYPE_IP;
 
202
        entry.route_dst.addr_bits = entry.route_gw.addr_bits = IP_ADDR_BITS;
 
203
 
 
204
        if ((fp = fopen(PROC_ROUTE_FILE, "r")) == NULL)
 
205
                return (-1);
 
206
 
 
207
        ret = 0;
 
208
        while (fgets(buf, sizeof(buf), fp) != NULL) {
 
209
                i = sscanf(buf,
 
210
                    "%16s %X %X %X %d %d %d %X %d %d %d\n",
 
211
                    ifbuf, &entry.route_dst.addr_ip, &entry.route_gw.addr_ip,
 
212
                    &iflags, &refcnt, &use, &metric, &mask, &mss, &win, &irtt);
 
213
                
 
214
                if (i < 10 || !(iflags & RTF_UP))
 
215
                        continue;
 
216
                
 
217
                if (entry.route_gw.addr_ip == IP_ADDR_ANY)
 
218
                        continue;
 
219
                
 
220
                entry.route_dst.addr_type = entry.route_gw.addr_type =
 
221
                    ADDR_TYPE_IP;
 
222
                
 
223
                if (addr_mtob(&mask, IP_ADDR_LEN,
 
224
                    &entry.route_dst.addr_bits) < 0)
 
225
                        continue;
 
226
                
 
227
                if ((ret = callback(&entry, arg)) != 0)
 
228
                        break;
 
229
        }
 
230
        if (ferror(fp)) {
 
231
                fclose(fp);
 
232
                return (-1);
 
233
        }
 
234
        fclose(fp);
 
235
        
 
236
        return (ret);
 
237
}
 
238
 
 
239
route_t *
 
240
route_close(route_t *r)
 
241
{
 
242
        if (r->fd > 0)
 
243
                close(r->fd);
 
244
        if (r->nlfd > 0)
 
245
                close(r->nlfd);
 
246
        free(r);
 
247
        return (NULL);
 
248
}