this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Initial net.route sysctl implementation

Only supports IPv4 right now

+233
+1
src/kernel/emulation/linux/CMakeLists.txt
··· 161 161 misc/sysctl_unspec.c 162 162 misc/sysctl_machdep.c 163 163 misc/sysctl_sysctl.c 164 + misc/sysctl_net.c 164 165 misc/getrlimit.c 165 166 misc/setrlimit.c 166 167 misc/gethostuuid.c
+2
src/kernel/emulation/linux/misc/sysctl.c
··· 11 11 #include "sysctl_kern.h" 12 12 #include "sysctl_machdep.h" 13 13 #include "sysctl_sysctl.h" 14 + #include "sysctl_net.h" 14 15 15 16 extern char *strchr(const char *s, int c); 16 17 extern int strncmp(const char *s1, const char *s2, __SIZE_TYPE__ n); ··· 27 28 { .oid = CTL_KERN, .type = CTLTYPE_NODE, .exttype = "", .name = "kern", .subctls = sysctls_kern }, 28 29 { .oid = CTL_MACHDEP, .type = CTLTYPE_NODE, .exttype = "", .name = "machdep", .subctls = sysctls_machdep }, 29 30 { .oid = _CTL_SYSCTL, .type = CTLTYPE_NODE, .exttype = "", .name = "sysctl", .subctls = sysctls_sysctl }, 31 + { .oid = CTL_NET, .type = CTLTYPE_NODE, .exttype = "", .name = "net", .subctls = sysctls_net }, 30 32 { .oid = -1 }, /* terminating entry */ 31 33 }; 32 34
+221
src/kernel/emulation/linux/misc/sysctl_net.c
··· 1 + #include "sysctl_net.h" 2 + #include "../network/socket.h" 3 + #include "../network/duct.h" 4 + #include "../ioctl/ioctl.h" 5 + #include "../unistd/close.h" 6 + #include <sys/errno.h> 7 + #include <net/route.h> 8 + #include <sys/socket.h> 9 + #include <net/if.h> 10 + #include <net/if_dl.h> 11 + #include <netinet/in.h> 12 + 13 + extern void* memset(void* destination, int value, size_t length); 14 + extern void* memcpy(void* destination, const void* source, size_t n); 15 + extern size_t strnlen(const char* string, size_t max_length); 16 + extern char* strncpy(char* destination, const char* source, size_t length); 17 + extern size_t strlcpy(char* destination, const char* source, size_t size); 18 + 19 + static sysctl_handler(handle_route); 20 + static int do_iflist(void* old, unsigned long* oldlen); 21 + 22 + #define LINUX_SIOCGIFCONF 0x8912 23 + #define LINUX_SIOCGIFHWADDR 0x8927 24 + #define LINUX_SIOCGIFBRDADDR 0x8919 25 + #define LINUX_SIOCGIFNETMASK 0x891b 26 + #define LINUX_IFNAMSIZ 16 27 + 28 + #define MAC_LENGTH 6 29 + 30 + struct linux_sockaddr { 31 + unsigned short sa_family; 32 + char sa_data[14]; 33 + }; 34 + 35 + struct linux_ifmap { 36 + unsigned long mem_start; 37 + unsigned long mem_end; 38 + unsigned short base_addr; 39 + unsigned char irq; 40 + unsigned char dma; 41 + unsigned char port; 42 + }; 43 + 44 + struct linux_ifreq { 45 + char lifr_name[LINUX_IFNAMSIZ]; 46 + union { 47 + struct linux_sockaddr lifr_addr; 48 + struct linux_sockaddr lifr_dstaddr; 49 + struct linux_sockaddr lifr_broadaddr; 50 + struct linux_sockaddr lifr_netmask; 51 + struct linux_sockaddr lifr_hwaddr; 52 + short lifr_flags; 53 + int lifr_ifindex; 54 + int lifr_metric; 55 + int lifr_mtu; 56 + struct linux_ifmap lifr_map; 57 + char lifr_slave[LINUX_IFNAMSIZ]; 58 + char lifr_newname[LINUX_IFNAMSIZ]; 59 + char* lifr_data; 60 + }; 61 + }; 62 + 63 + // arbitrary number; only exists to avoid blowing up the stack 64 + #define IFC_MAX_INTERFACES 5 65 + 66 + struct linux_ifconf { 67 + int lifc_len; 68 + union { 69 + char* lifc_buf; 70 + struct linux_ifreq* lifc_req; 71 + }; 72 + }; 73 + 74 + enum { 75 + _NET_ROUTE = 17, 76 + }; 77 + 78 + enum { 79 + _NET_RT_IFLIST = 3, 80 + }; 81 + 82 + const struct known_sysctl sysctls_net[] = { 83 + // technically a CTLTYPE_NODE in XNU, but for us that means that it has children and isn't a variable in and of itself. 84 + // the actual value doesn't really matter as long as it's not CTLTYPE_NODE 85 + { .oid = _NET_ROUTE, .type = CTLTYPE_OPAQUE, .exttype = "", .name = "route", .handler = handle_route }, 86 + { .oid = -1 }, 87 + }; 88 + 89 + static unsigned long round_up_sizeof_u32(unsigned long number) { 90 + return (number + (sizeof(uint32_t) - 1)) & ~(sizeof(uint32_t) - 1); 91 + }; 92 + 93 + static int do_iflist(void* old, unsigned long* oldlen) { 94 + // we only do IPv4 addresses for now 95 + int tmp_sock; 96 + char buf[IFC_MAX_INTERFACES * sizeof(struct linux_ifreq)]; 97 + struct linux_ifconf lifc = { 98 + .lifc_len = sizeof(buf), 99 + .lifc_buf = buf, 100 + }; 101 + int status = 0; 102 + char* old_ptr = old; 103 + unsigned long total_len = 0; 104 + 105 + if ((status = tmp_sock = sys_socket(AF_INET, SOCK_DGRAM, 0)) < 0) 106 + goto out; 107 + 108 + if ((status = __real_ioctl(tmp_sock, LINUX_SIOCGIFCONF, &lifc)) < 0) 109 + goto out; 110 + 111 + for (int i = 0; i < lifc.lifc_len; i += sizeof(struct linux_ifreq)) { 112 + struct linux_ifreq* curr = &lifc.lifc_req[i / sizeof(struct linux_ifreq)]; 113 + size_t name_len = strnlen(curr->lifr_name, sizeof(curr->lifr_name)); 114 + size_t additional_sockaddr_len = name_len + MAC_LENGTH; 115 + additional_sockaddr_len = (additional_sockaddr_len <= sizeof(((struct sockaddr_dl*)NULL)->sdl_data)) ? 0 : (additional_sockaddr_len - sizeof(((struct sockaddr_dl*)NULL)->sdl_data)); 116 + size_t ifm_length = sizeof(struct if_msghdr) + round_up_sizeof_u32(sizeof(struct sockaddr_dl) + additional_sockaddr_len); 117 + size_t ifam_length = sizeof(struct ifa_msghdr) + round_up_sizeof_u32(sizeof(struct sockaddr)) * 3; 118 + // technically not correct; SIOCGIFCONF could return the same interfaces in a different order on each call 119 + // but this is enough for our purposes 120 + size_t iface_idx = (i / sizeof(struct linux_ifreq)) + 1; 121 + 122 + if (old && *oldlen >= total_len + ifm_length) { 123 + struct if_msghdr* ifm = (void*)old_ptr; 124 + struct sockaddr_dl* dl = (void*)(old_ptr + sizeof(struct if_msghdr)); 125 + struct linux_ifreq tmp; 126 + 127 + memset(old_ptr, 0, ifm_length); 128 + 129 + ifm->ifm_msglen = ifm_length; 130 + ifm->ifm_index = iface_idx; 131 + ifm->ifm_type = RTM_IFINFO; 132 + ifm->ifm_version = RTM_VERSION; 133 + ifm->ifm_addrs = RTA_IFP; 134 + 135 + dl->sdl_len = sizeof(struct sockaddr_dl) + additional_sockaddr_len; 136 + dl->sdl_family = AF_LINK; 137 + dl->sdl_index = ifm->ifm_index; 138 + /* dl->sdl_type = 0; */ // TODO: determine this somehow 139 + dl->sdl_nlen = name_len; 140 + dl->sdl_alen = MAC_LENGTH; 141 + dl->sdl_slen = 0; // ??? 142 + 143 + memcpy(dl->sdl_data, curr->lifr_name, name_len); 144 + 145 + // grab the MAC 146 + memcpy(tmp.lifr_name, curr->lifr_name, sizeof(curr->lifr_name)); 147 + if ((status = __real_ioctl(tmp_sock, LINUX_SIOCGIFHWADDR, &tmp)) < 0) 148 + goto out; 149 + memcpy(LLADDR(dl), tmp.lifr_hwaddr.sa_data, MAC_LENGTH); 150 + 151 + old_ptr += ifm_length; 152 + } 153 + total_len += ifm_length; 154 + 155 + if (old && *oldlen >= total_len + ifam_length) { 156 + struct ifa_msghdr* ifam = (void*)old_ptr; 157 + struct sockaddr* netmask = (void*)(old_ptr + sizeof(struct ifa_msghdr)); 158 + struct sockaddr* ip_addr = (void*)(old_ptr + sizeof(struct ifa_msghdr) + round_up_sizeof_u32(sizeof(struct sockaddr))); 159 + struct sockaddr* broad_addr = (void*)(old_ptr + sizeof(struct ifa_msghdr) + round_up_sizeof_u32(sizeof(struct sockaddr)) * 2); 160 + struct linux_ifreq tmp; 161 + 162 + memset(old_ptr, 0, ifam_length); 163 + 164 + ifam->ifam_msglen = ifam_length; 165 + ifam->ifam_index = iface_idx; 166 + ifam->ifam_type = RTM_NEWADDR; 167 + ifam->ifam_version = RTM_VERSION; 168 + ifam->ifam_addrs = RTA_NETMASK | RTA_IFA | RTA_BRD; 169 + 170 + sockaddr_fixup_from_linux((struct sockaddr_fixup*)ip_addr, &curr->lifr_addr, sizeof(struct linux_sockaddr)); 171 + 172 + memcpy(tmp.lifr_name, curr->lifr_name, sizeof(curr->lifr_name)); 173 + 174 + // get the netmask 175 + if ((status = __real_ioctl(tmp_sock, LINUX_SIOCGIFNETMASK, &tmp)) < 0) 176 + goto out; 177 + sockaddr_fixup_from_linux((struct sockaddr_fixup*)netmask, &tmp.lifr_netmask, sizeof(struct linux_sockaddr)); 178 + 179 + // get the broadcast address 180 + if ((status = __real_ioctl(tmp_sock, LINUX_SIOCGIFBRDADDR, &tmp)) < 0) 181 + goto out; 182 + sockaddr_fixup_from_linux((struct sockaddr_fixup*)broad_addr, &tmp.lifr_broadaddr, sizeof(struct linux_sockaddr)); 183 + 184 + old_ptr += ifam_length; 185 + } 186 + total_len += ifam_length; 187 + } 188 + 189 + // we succeeded if we got here 190 + status = 0; 191 + 192 + out: 193 + if (tmp_sock >= 0) { 194 + // ignore errors while closing 195 + close_internal(tmp_sock); 196 + } 197 + *oldlen = total_len; 198 + return status; 199 + }; 200 + 201 + static sysctl_handler(handle_route) { 202 + int status = 0; 203 + 204 + if (nlen != 6) { 205 + status = -EINVAL; 206 + goto out; 207 + } 208 + 209 + // name[4] is the desired operation 210 + switch (name[4]) { 211 + case _NET_RT_IFLIST: 212 + status = do_iflist(old, oldlen); 213 + break; 214 + default: 215 + status = -EINVAL; 216 + goto out; 217 + } 218 + 219 + out: 220 + return status; 221 + };
+9
src/kernel/emulation/linux/misc/sysctl_net.h
··· 1 + #ifndef _DARLING_EMULATION_MISC_SYSCTL_NET_H 2 + #define _DARLING_EMULATION_MISC_SYSCTL_NET_H 3 + 4 + #include "sysctl.h" 5 + 6 + extern const struct known_sysctl sysctls_net[]; 7 + 8 + #endif // _DARLING_EMULATION_MISC_SYSCTL_NET_H 9 +