Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sbin/ifconfig/af_inet.c
39475 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1983, 1993
5
* The Regents of the University of California. All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
* 3. Neither the name of the University nor the names of its contributors
16
* may be used to endorse or promote products derived from this software
17
* without specific prior written permission.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
* SUCH DAMAGE.
30
*/
31
32
#include <sys/param.h>
33
#include <sys/ioctl.h>
34
#include <sys/socket.h>
35
#include <net/if.h>
36
37
#include <ctype.h>
38
#include <err.h>
39
#include <stdio.h>
40
#include <stdlib.h>
41
#include <string.h>
42
#include <unistd.h>
43
#include <ifaddrs.h>
44
45
#include <netinet/in.h>
46
#include <netinet/in_var.h>
47
#include <arpa/inet.h>
48
#include <netdb.h>
49
50
#include "ifconfig.h"
51
#include "ifconfig_netlink.h"
52
53
#ifdef WITHOUT_NETLINK
54
static struct in_aliasreq in_addreq;
55
static struct ifreq in_ridreq;
56
#else
57
struct in_px {
58
struct in_addr addr;
59
int plen;
60
bool addrset;
61
bool maskset;
62
};
63
struct in_pdata {
64
struct in_px addr;
65
struct in_px dst_addr;
66
struct in_px brd_addr;
67
uint32_t flags;
68
uint32_t vhid;
69
};
70
static struct in_pdata in_add, in_del;
71
#endif
72
73
static char addr_buf[NI_MAXHOST]; /*for getnameinfo()*/
74
extern char *f_inet, *f_addr;
75
76
static void
77
print_addr(struct sockaddr_in *sin)
78
{
79
int error, n_flags;
80
81
if (f_addr != NULL && strcmp(f_addr, "fqdn") == 0)
82
n_flags = 0;
83
else if (f_addr != NULL && strcmp(f_addr, "host") == 0)
84
n_flags = NI_NOFQDN;
85
else
86
n_flags = NI_NUMERICHOST;
87
88
error = getnameinfo((struct sockaddr *)sin, sin->sin_len, addr_buf,
89
sizeof(addr_buf), NULL, 0, n_flags);
90
91
if (error)
92
inet_ntop(AF_INET, &sin->sin_addr, addr_buf, sizeof(addr_buf));
93
94
printf("\tinet %s", addr_buf);
95
}
96
97
#ifdef WITHOUT_NETLINK
98
static void
99
in_status(if_ctx *ctx __unused, const struct ifaddrs *ifa)
100
{
101
struct sockaddr_in *sin, null_sin = {};
102
103
sin = satosin(ifa->ifa_addr);
104
if (sin == NULL)
105
return;
106
107
print_addr(sin);
108
109
if (ifa->ifa_flags & IFF_POINTOPOINT) {
110
sin = satosin(ifa->ifa_dstaddr);
111
if (sin == NULL)
112
sin = &null_sin;
113
printf(" --> %s", inet_ntoa(sin->sin_addr));
114
}
115
116
sin = satosin(ifa->ifa_netmask);
117
if (sin == NULL)
118
sin = &null_sin;
119
if (f_inet != NULL && strcmp(f_inet, "cidr") == 0) {
120
int cidr = 32;
121
unsigned long smask;
122
123
smask = ntohl(sin->sin_addr.s_addr);
124
while ((smask & 1) == 0) {
125
smask = smask >> 1;
126
cidr--;
127
if (cidr == 0)
128
break;
129
}
130
printf("/%d", cidr);
131
} else if (f_inet != NULL && strcmp(f_inet, "dotted") == 0)
132
printf(" netmask %s", inet_ntoa(sin->sin_addr));
133
else
134
printf(" netmask 0x%lx", (unsigned long)ntohl(sin->sin_addr.s_addr));
135
136
if (ifa->ifa_flags & IFF_BROADCAST) {
137
sin = satosin(ifa->ifa_broadaddr);
138
if (sin != NULL && sin->sin_addr.s_addr != 0)
139
printf(" broadcast %s", inet_ntoa(sin->sin_addr));
140
}
141
142
print_vhid(ifa);
143
144
putchar('\n');
145
}
146
147
#else
148
static struct in_addr
149
get_mask(int plen)
150
{
151
struct in_addr a;
152
153
a.s_addr = htonl(plen ? ~((1 << (32 - plen)) - 1) : 0);
154
155
return (a);
156
}
157
158
static void
159
in_status_nl(if_ctx *ctx __unused, if_link_t *link, if_addr_t *ifa)
160
{
161
struct sockaddr_in *sin = satosin(ifa->ifa_local);
162
int plen = ifa->ifa_prefixlen;
163
164
print_addr(sin);
165
166
if (link->ifi_flags & IFF_POINTOPOINT) {
167
struct sockaddr_in *dst = satosin(ifa->ifa_address);
168
169
printf(" --> %s", inet_ntoa(dst->sin_addr));
170
}
171
if (f_inet != NULL && strcmp(f_inet, "cidr") == 0) {
172
printf("/%d", plen);
173
} else if (f_inet != NULL && strcmp(f_inet, "dotted") == 0)
174
printf(" netmask %s", inet_ntoa(get_mask(plen)));
175
else
176
printf(" netmask 0x%lx", (unsigned long)ntohl(get_mask(plen).s_addr));
177
178
if ((link->ifi_flags & IFF_BROADCAST) && plen != 0) {
179
struct sockaddr_in *brd = satosin(ifa->ifa_broadcast);
180
if (brd != NULL)
181
printf(" broadcast %s", inet_ntoa(brd->sin_addr));
182
}
183
184
if (ifa->ifaf_vhid != 0)
185
printf(" vhid %d", ifa->ifaf_vhid);
186
187
putchar('\n');
188
}
189
#endif
190
191
192
#ifdef WITHOUT_NETLINK
193
#define SIN(x) ((struct sockaddr_in *) &(x))
194
static struct sockaddr_in *sintab[] = {
195
SIN(in_ridreq.ifr_addr), SIN(in_addreq.ifra_addr),
196
SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)
197
};
198
199
static void
200
in_copyaddr(if_ctx *ctx __unused, int to, int from)
201
{
202
memcpy(sintab[to], sintab[from], sizeof(struct sockaddr_in));
203
}
204
205
static void
206
in_getaddr(const char *s, int which)
207
{
208
struct sockaddr_in *sin = sintab[which];
209
struct hostent *hp;
210
struct netent *np;
211
212
sin->sin_len = sizeof(*sin);
213
sin->sin_family = AF_INET;
214
215
if (which == ADDR) {
216
char *p = NULL;
217
218
if((p = strrchr(s, '/')) != NULL) {
219
const char *errstr;
220
/* address is `name/masklen' */
221
int masklen = 0;
222
struct sockaddr_in *min = sintab[MASK];
223
*p = '\0';
224
if (!isdigit(*(p + 1)))
225
errstr = "invalid";
226
else
227
masklen = (int)strtonum(p + 1, 0, 32, &errstr);
228
if (errstr != NULL) {
229
*p = '/';
230
errx(1, "%s: bad value (width %s)", s, errstr);
231
}
232
min->sin_family = AF_INET;
233
min->sin_len = sizeof(*min);
234
min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) &
235
0xffffffff);
236
}
237
}
238
239
if (inet_aton(s, &sin->sin_addr))
240
return;
241
if ((hp = gethostbyname(s)) != NULL)
242
bcopy(hp->h_addr, (char *)&sin->sin_addr,
243
MIN((size_t)hp->h_length, sizeof(sin->sin_addr)));
244
else if ((np = getnetbyname(s)) != NULL)
245
sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
246
else
247
errx(1, "%s: bad value", s);
248
}
249
250
#else
251
252
static struct in_px *sintab_nl[] = {
253
&in_del.addr, /* RIDADDR */
254
&in_add.addr, /* ADDR */
255
NULL, /* MASK */
256
&in_add.dst_addr, /* DSTADDR*/
257
&in_add.brd_addr, /* BRDADDR*/
258
};
259
260
static void
261
in_copyaddr(if_ctx *ctx __unused, int to, int from)
262
{
263
sintab_nl[to]->addr = sintab_nl[from]->addr;
264
sintab_nl[to]->addrset = sintab_nl[from]->addrset;
265
}
266
267
static void
268
in_getip(const char *addr_str, struct in_addr *ip)
269
{
270
struct hostent *hp;
271
struct netent *np;
272
273
if (inet_aton(addr_str, ip))
274
return;
275
if ((hp = gethostbyname(addr_str)) != NULL)
276
bcopy(hp->h_addr, (char *)ip,
277
MIN((size_t)hp->h_length, sizeof(ip)));
278
else if ((np = getnetbyname(addr_str)) != NULL)
279
*ip = inet_makeaddr(np->n_net, INADDR_ANY);
280
else
281
errx(1, "%s: bad value", addr_str);
282
}
283
284
static void
285
in_getaddr(const char *s, int which)
286
{
287
struct in_px *px = sintab_nl[which];
288
289
if (which == MASK) {
290
struct in_px *px_addr = sintab_nl[ADDR];
291
struct in_addr mask = {};
292
293
in_getip(s, &mask);
294
px_addr->plen = __bitcount32(mask.s_addr);
295
px_addr->maskset = true;
296
return;
297
}
298
299
if (which == ADDR) {
300
char *p = NULL;
301
302
if((p = strrchr(s, '/')) != NULL) {
303
const char *errstr;
304
/* address is `name/masklen' */
305
int masklen;
306
*p = '\0';
307
if (!isdigit(*(p + 1)))
308
errstr = "invalid";
309
else
310
masklen = (int)strtonum(p + 1, 0, 32, &errstr);
311
if (errstr != NULL) {
312
*p = '/';
313
errx(1, "%s: bad value (width %s)", s, errstr);
314
}
315
px->plen = masklen;
316
px->maskset = true;
317
}
318
}
319
320
in_getip(s, &px->addr);
321
px->addrset = true;
322
}
323
324
/*
325
* Deletes the first found IPv4 interface address for the interface.
326
*
327
* This function provides SIOCDIFADDR semantics missing in Netlink.
328
* When no valid IPv4 address is specified (sin_family or sin_len is wrong) to
329
* the SIOCDIFADDR call, it deletes the first found IPv4 address on the interface.
330
* 'ifconfig IFNAME inet addr/prefix' relies on that behavior, as it
331
* executes empty SIOCDIFADDR before adding a new address.
332
*/
333
static int
334
in_delete_first_nl(if_ctx *ctx)
335
{
336
struct nlmsghdr *hdr;
337
struct ifaddrmsg *ifahdr;
338
uint32_t nlmsg_seq;
339
struct in_addr addr;
340
struct snl_writer nw = {};
341
struct snl_errmsg_data e = {};
342
struct snl_state *ss = ctx->io_ss;
343
bool found = false;
344
345
uint32_t ifindex = if_nametoindex_nl(ss, ctx->ifname);
346
if (ifindex == 0) {
347
/* No interface with the desired name, nothing to delete */
348
return (EADDRNOTAVAIL);
349
}
350
351
snl_init_writer(ss, &nw);
352
hdr = snl_create_msg_request(&nw, NL_RTM_GETADDR);
353
hdr->nlmsg_flags |= NLM_F_DUMP;
354
ifahdr = snl_reserve_msg_object(&nw, struct ifaddrmsg);
355
ifahdr->ifa_family = AF_INET;
356
ifahdr->ifa_index = ifindex;
357
358
if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ss, hdr))
359
return (EINVAL);
360
361
nlmsg_seq = hdr->nlmsg_seq;
362
while ((hdr = snl_read_reply_multi(ss, nlmsg_seq, &e)) != NULL) {
363
struct snl_parsed_addr attrs = {};
364
if (snl_parse_nlmsg(ss, hdr, &snl_rtm_addr_parser, &attrs)) {
365
addr = satosin(attrs.ifa_local)->sin_addr;
366
ifindex = attrs.ifa_index;
367
found = true;
368
break;
369
} else
370
return (EINVAL);
371
}
372
if (e.error != 0) {
373
if (e.error_str != NULL)
374
warnx("%s(): %s", __func__, e.error_str);
375
return (e.error);
376
}
377
378
if (!found)
379
return (0);
380
381
/* Try to delete the found address */
382
snl_init_writer(ss, &nw);
383
hdr = snl_create_msg_request(&nw, NL_RTM_DELADDR);
384
ifahdr = snl_reserve_msg_object(&nw, struct ifaddrmsg);
385
ifahdr->ifa_family = AF_INET;
386
ifahdr->ifa_index = ifindex;
387
snl_add_msg_attr_ip4(&nw, IFA_LOCAL, &addr);
388
389
if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ss, hdr))
390
return (EINVAL);
391
memset(&e, 0, sizeof(e));
392
snl_read_reply_code(ss, hdr->nlmsg_seq, &e);
393
if (e.error_str != NULL)
394
warnx("%s(): %s", __func__, e.error_str);
395
396
return (e.error);
397
}
398
399
400
static int
401
in_exec_nl(if_ctx *ctx, unsigned long action, void *data)
402
{
403
struct in_pdata *pdata = (struct in_pdata *)data;
404
struct snl_writer nw = {};
405
406
if (action == NL_RTM_DELADDR && !pdata->addr.addrset)
407
return (in_delete_first_nl(ctx));
408
409
snl_init_writer(ctx->io_ss, &nw);
410
struct nlmsghdr *hdr = snl_create_msg_request(&nw, action);
411
struct ifaddrmsg *ifahdr = snl_reserve_msg_object(&nw, struct ifaddrmsg);
412
413
ifahdr->ifa_family = AF_INET;
414
ifahdr->ifa_prefixlen = pdata->addr.plen;
415
ifahdr->ifa_index = if_nametoindex_nl(ctx->io_ss, ctx->ifname);
416
417
snl_add_msg_attr_ip4(&nw, IFA_LOCAL, &pdata->addr.addr);
418
if (action == NL_RTM_NEWADDR && pdata->dst_addr.addrset)
419
snl_add_msg_attr_ip4(&nw, IFA_ADDRESS, &pdata->dst_addr.addr);
420
if (action == NL_RTM_NEWADDR && pdata->brd_addr.addrset)
421
snl_add_msg_attr_ip4(&nw, IFA_BROADCAST, &pdata->brd_addr.addr);
422
423
int off = snl_add_msg_attr_nested(&nw, IFA_FREEBSD);
424
snl_add_msg_attr_u32(&nw, IFAF_FLAGS, pdata->flags);
425
if (pdata->vhid != 0)
426
snl_add_msg_attr_u32(&nw, IFAF_VHID, pdata->vhid);
427
snl_end_attr_nested(&nw, off);
428
429
if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ctx->io_ss, hdr))
430
return (0);
431
432
struct snl_errmsg_data e = {};
433
snl_read_reply_code(ctx->io_ss, hdr->nlmsg_seq, &e);
434
if (e.error_str != NULL)
435
warnx("%s(): %s", __func__, e.error_str);
436
437
return (e.error);
438
}
439
#endif
440
441
static void
442
err_nomask(int ifflags)
443
{
444
if ((ifflags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) {
445
errx(1, "ERROR: setting interface address without mask is no longer supported.");
446
}
447
}
448
449
static void
450
in_postproc(if_ctx *ctx __unused, int newaddr, int ifflags)
451
{
452
#ifdef WITHOUT_NETLINK
453
if (sintab[ADDR]->sin_len != 0 && sintab[MASK]->sin_len == 0 && newaddr) {
454
err_nomask(ifflags);
455
}
456
#else
457
if (sintab_nl[ADDR]->addrset && !sintab_nl[ADDR]->maskset && newaddr) {
458
err_nomask(ifflags);
459
}
460
#endif
461
}
462
463
static void
464
in_status_tunnel(if_ctx *ctx)
465
{
466
char src[NI_MAXHOST];
467
char dst[NI_MAXHOST];
468
struct ifreq ifr;
469
const struct sockaddr *sa = (const struct sockaddr *) &ifr.ifr_addr;
470
471
memset(&ifr, 0, sizeof(ifr));
472
strlcpy(ifr.ifr_name, ctx->ifname, IFNAMSIZ);
473
474
if (ioctl_ctx(ctx, SIOCGIFPSRCADDR, (caddr_t)&ifr) < 0)
475
return;
476
if (sa->sa_family != AF_INET)
477
return;
478
if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, NI_NUMERICHOST) != 0)
479
src[0] = '\0';
480
481
if (ioctl_ctx(ctx, SIOCGIFPDSTADDR, (caddr_t)&ifr) < 0)
482
return;
483
if (sa->sa_family != AF_INET)
484
return;
485
if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, NI_NUMERICHOST) != 0)
486
dst[0] = '\0';
487
488
printf("\ttunnel inet %s --> %s\n", src, dst);
489
}
490
491
static void
492
in_set_tunnel(if_ctx *ctx, struct addrinfo *srcres, struct addrinfo *dstres)
493
{
494
struct in_aliasreq addreq;
495
496
memset(&addreq, 0, sizeof(addreq));
497
strlcpy(addreq.ifra_name, ctx->ifname, IFNAMSIZ);
498
memcpy(&addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
499
memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, dstres->ai_addr->sa_len);
500
501
if (ioctl_ctx(ctx, SIOCSIFPHYADDR, &addreq) < 0)
502
warn("SIOCSIFPHYADDR");
503
}
504
505
static void
506
in_set_vhid(int vhid)
507
{
508
#ifdef WITHOUT_NETLINK
509
in_addreq.ifra_vhid = vhid;
510
#else
511
in_add.vhid = (uint32_t)vhid;
512
#endif
513
}
514
515
static struct afswtch af_inet = {
516
.af_name = "inet",
517
.af_af = AF_INET,
518
#ifdef WITHOUT_NETLINK
519
.af_status = in_status,
520
#else
521
.af_status = in_status_nl,
522
#endif
523
.af_getaddr = in_getaddr,
524
.af_copyaddr = in_copyaddr,
525
.af_postproc = in_postproc,
526
.af_status_tunnel = in_status_tunnel,
527
.af_settunnel = in_set_tunnel,
528
.af_setvhid = in_set_vhid,
529
#ifdef WITHOUT_NETLINK
530
.af_difaddr = SIOCDIFADDR,
531
.af_aifaddr = SIOCAIFADDR,
532
.af_ridreq = &in_ridreq,
533
.af_addreq = &in_addreq,
534
.af_exec = af_exec_ioctl,
535
#else
536
.af_difaddr = NL_RTM_DELADDR,
537
.af_aifaddr = NL_RTM_NEWADDR,
538
.af_ridreq = &in_del,
539
.af_addreq = &in_add,
540
.af_exec = in_exec_nl,
541
#endif
542
};
543
544
static __constructor void
545
inet_ctor(void)
546
{
547
548
#ifndef RESCUE
549
if (!feature_present("inet"))
550
return;
551
#endif
552
af_register(&af_inet);
553
}
554
555