On macOS, I have a utun interface that I've created. I'd like to, in C, assign it an IPv4 address and netmask. The former I can do via the SIOCSIFADDR ioctl command. However, I'm having some trouble with setting the netmask. On Linux, I'd do
struct sockaddr_in addr = {.sin_family = AF_INET};
struct ifreq ifr = {.ifr_name = "utun5"};
inet_pton(AF_INET, "255.255.255.0", &addr.sin_addr);
memcpy(&ifr.ifr_netmask, &addr, sizeof(addr));
if ( ioctl(sock, SIOCSIFNETMASK, &ifr) == -1 ) {
// handle the error
}
My problem is, though sys/sockio.h on my Macbook defines the value SIOCSIFNETMASK, struct ifreq doesn't appear to have any netmask field. net/if.h shows me
struct ifreq {
char ifr_name[IFNAMESIZ];
union {
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
short ifru_flags;
...
On Linux, it looks like
struct ifreq {
union {
char ifrn_name[IFNAMSIZ];
} ifr_ifrn;
union {
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
...
Now, it occurred to me that this is just a union and it shouldn't matter that ifru_netmask isn't defined on macOS. I can just set the netmask value in ifru_addr. I tried that and, while the SIOCSIFNETMASK command succeeded, ifconfig shows that the device has its default netmask of 0xff000000:
utun5: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1500
inet 1.2.3.4 --> 0.0.0.0 netmask 0xff000000
Am I missing something obvious?
Here's my MRE:
#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_utun.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/kern_control.h>
#include <sys/kern_event.h>
#include <sys/socket.h>
#include <unistd.h>
int
tun_device_create(char *if_name)
{
int fd;
struct ctl_info info = {0};
struct sockaddr_ctl addr = {
.sc_family = AF_SYSTEM, .sc_len = sizeof(struct sockaddr_ctl), .ss_sysaddr = AF_SYS_CONTROL};
fd = socket(AF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
if (fd < 0) {
perror("socket (AF_SYSTEM)");
return -1;
}
snprintf(info.ctl_name, sizeof(info.ctl_name), "%s", UTUN_CONTROL_NAME);
if (ioctl(fd, CTLIOCGINFO, &info) == -1) {
perror("ioctl (CTLIOCGINFO)");
goto error;
}
addr.sc_id = info.ctl_id;
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
perror("connect (AF_SYSTEM)");
goto error;
}
if (getsockopt(fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, if_name, &(socklen_t){IFNAMSIZ}) != 0) {
perror("getsockopt (SYSPROTO_CONTROL)");
goto error;
}
return fd;
error:
close(fd);
return -1;
}
int
set_addr_and_bring_up(const char *if_name, const char *ipv4_address, const char *ipv4_netmask)
{
int sock, ret = -1;
struct ifreq ifr = {0};
struct sockaddr_in *addr = (struct sockaddr_in *)&ifr.ifr_addr;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket");
return -1;
}
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", if_name);
addr->sin_family = AF_INET;
inet_pton(AF_INET, ipv4_address, &addr->sin_addr);
if (ioctl(sock, SIOCSIFADDR, &ifr) == -1) {
perror("ioctl (SIOCSIFADDR)");
goto done;
}
inet_pton(AF_INET, ipv4_netmask, &addr->sin_addr);
if (ioctl(sock, SIOCSIFNETMASK, &ifr) == -1) {
perror("ioctl (SIOCSIFNETMASK)");
goto done;
}
ifr.ifr_flags = IFF_UP;
if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) {
perror("ioctl (SIOCSIFFLAGS)");
goto done;
}
ret = 0;
done:
close(sock);
return ret;
}
int
main()
{
int fd;
char if_name[IFNAMSIZ];
fd = tun_device_create(if_name);
if (fd < 0) {
return 1;
}
if (set_addr_and_bring_up(if_name, "1.2.3.4", "255.255.255.0") != 0) {
close(fd);
return 1;
}
printf("Tun device created: %s\n", if_name);
pause();
close(fd);
return 0;
}
if (set_addr_and_bring_up(if_name, "1.2.3.4", "255.255.255.0") != 0) {
close(fd);
return 1;
}
should be using a "valid" address, i.e.
if (set_addr_and_bring_up(if_name, "192.168.0.1", "255.255.255.0") != 0) {
close(fd);
return 1;
}
utun7: flags=8050<POINTOPOINT,RUNNING,MULTICAST> mtu 1500
inet 192.168.0.1 --> 0.0.0.0 netmask 0xffffff00
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With