99#include <linux/wireguard.h>
1010#include "netlink.h"
1111#endif
12+ #ifdef __OpenBSD__
13+ #include <net/if_wg.h>
14+ #endif
1215#include <netinet/in.h>
1316#include <sys/socket.h>
1417#include <net/if.h>
@@ -922,13 +925,269 @@ static int kernel_get_device(struct wgdevice **device, const char *iface)
922925}
923926#endif
924927
928+ #ifdef __OpenBSD__
929+ int s = -1 ;
930+
931+ void
932+ getsock ()
933+ {
934+ if (s < 0 )
935+ s = socket (AF_INET , SOCK_DGRAM , 0 );
936+ }
937+
938+ static int kernel_get_wireguard_interfaces (struct string_list * list )
939+ {
940+ struct ifgroupreq ifgr ;
941+ struct ifg_req * ifg ;
942+ size_t len = 0 ;
943+ int ret = 0 ;
944+
945+ getsock ();
946+
947+ bzero (& ifgr , sizeof (ifgr ));
948+ strlcpy (ifgr .ifgr_name , "wg" , sizeof (ifgr .ifgr_name ));
949+
950+ if (ioctl (s , SIOCGIFGMEMB , (caddr_t )& ifgr ) == -1 )
951+ return errno ;
952+
953+ len = ifgr .ifgr_len ;
954+ if ((ifgr .ifgr_groups = calloc (1 , len )) == NULL )
955+ return errno ;
956+ if (ioctl (s , SIOCGIFGMEMB , (caddr_t )& ifgr ) == -1 ) {
957+ ret = errno ;
958+ goto out ;
959+ }
960+
961+ for (ifg = ifgr .ifgr_groups ; ifg && len > 0 ; ifg ++ ) {
962+ if ((ret = string_list_add (list , ifg -> ifgrq_member )) < 0 )
963+ goto out ;
964+ len -= sizeof (struct ifg_req );
965+ }
966+
967+ out :
968+ free (ifgr .ifgr_groups );
969+ return ret ;
970+ }
971+
972+ static int kernel_get_device (struct wgdevice * * device , const char * iface )
973+ {
974+ struct wg_data_io wgdata ;
975+ struct wg_interface_io * wg_iface ;
976+ struct wg_peer_io * wg_peer ;
977+ struct wg_aip_io * wg_aip ;
978+
979+ struct wgdevice * dev ;
980+ struct wgpeer * peer ;
981+ struct wgallowedip * aip ;
982+
983+ size_t size ;
984+
985+ getsock ();
986+
987+ * device = NULL ;
988+
989+ strlcpy (wgdata .wgd_name , iface , sizeof (wgdata .wgd_name ));
990+ wgdata .wgd_size = size = 0 ;
991+ wgdata .wgd_mem = NULL ;
992+
993+ if (ioctl (s , SIOCGWG , (caddr_t )& wgdata ) == -1 &&
994+ (errno == ENOTTY || errno == EPERM ))
995+ return - errno ;
996+
997+ while (size < wgdata .wgd_size ) {
998+ size = wgdata .wgd_size ;
999+ wgdata .wgd_mem = realloc (wgdata .wgd_mem , size );
1000+ if (ioctl (s , SIOCGWG , (caddr_t )& wgdata ) == -1 )
1001+ return - errno ;
1002+ }
1003+
1004+ wg_iface = wgdata .wgd_mem ;
1005+
1006+ if ((dev = calloc (1 , sizeof (* dev ))) == NULL )
1007+ return - errno ;
1008+ strlcpy (dev -> name , iface , sizeof (dev -> name ));
1009+
1010+ if (wg_iface -> i_flags & WG_INTERFACE_HAS_RTABLE ) {
1011+ dev -> fwmark = wg_iface -> i_rtable ;
1012+ dev -> flags |= WGDEVICE_HAS_FWMARK ;
1013+ }
1014+
1015+ if (wg_iface -> i_flags & WG_INTERFACE_HAS_PORT ) {
1016+ dev -> listen_port = ntohs (wg_iface -> i_port );
1017+ dev -> flags |= WGDEVICE_HAS_LISTEN_PORT ;
1018+ }
1019+
1020+ if (wg_iface -> i_flags & WG_INTERFACE_HAS_PUBLIC ) {
1021+ memcpy (dev -> public_key , wg_iface -> i_public , WG_KEY_SIZE );
1022+ dev -> flags |= WGDEVICE_HAS_PUBLIC_KEY ;
1023+ }
1024+
1025+ if (wg_iface -> i_flags & WG_INTERFACE_HAS_PRIVATE ) {
1026+ memcpy (dev -> private_key , wg_iface -> i_private , WG_KEY_SIZE );
1027+ dev -> flags |= WGDEVICE_HAS_PRIVATE_KEY ;
1028+ }
1029+
1030+ for (wg_peer = wg_iface -> i_peers ; wg_peer != NULL ; wg_peer = wg_peer -> p_next ) {
1031+ if ((peer = calloc (1 , sizeof (* peer ))) == NULL )
1032+ return - errno ;
1033+
1034+ if (dev -> first_peer == NULL )
1035+ dev -> first_peer = peer ;
1036+ else
1037+ dev -> last_peer -> next_peer = peer ;
1038+ dev -> last_peer = peer ;
1039+
1040+ if (wg_peer -> p_flags & WG_PEER_HAS_PUBLIC ) {
1041+ memcpy (peer -> public_key , wg_peer -> p_public , WG_KEY_SIZE );
1042+ peer -> flags |= WGPEER_HAS_PUBLIC_KEY ;
1043+ }
1044+
1045+ if (wg_peer -> p_flags & WG_PEER_HAS_PSK ) {
1046+ memcpy (peer -> preshared_key , wg_peer -> p_psk , WG_KEY_SIZE );
1047+ peer -> flags |= WGPEER_HAS_PRESHARED_KEY ;
1048+ }
1049+
1050+ if (wg_peer -> p_flags & WG_PEER_HAS_PKA ) {
1051+ peer -> persistent_keepalive_interval = wg_peer -> p_pka ;
1052+ peer -> flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL ;
1053+ }
1054+
1055+ if (wg_peer -> p_flags & WG_PEER_HAS_SOCKADDR )
1056+ memcpy (& peer -> endpoint .addr , & wg_peer -> p_sa ,
1057+ wg_peer -> p_sa .sa_len );
1058+
1059+ peer -> rx_bytes = wg_peer -> p_rxbytes ;
1060+ peer -> tx_bytes = wg_peer -> p_txbytes ;
1061+
1062+ peer -> last_handshake_time .tv_sec = wg_peer -> p_last_handshake .tv_sec ;
1063+ peer -> last_handshake_time .tv_nsec = wg_peer -> p_last_handshake .tv_nsec ;
1064+
1065+ for (wg_aip = wg_peer -> p_aips ; wg_aip != NULL ; wg_aip = wg_aip -> a_next ) {
1066+ if ((aip = calloc (1 , sizeof (* aip ))) == NULL )
1067+ return - errno ;
1068+
1069+ if (peer -> first_allowedip == NULL )
1070+ peer -> first_allowedip = aip ;
1071+ else
1072+ peer -> last_allowedip -> next_allowedip = aip ;
1073+ peer -> last_allowedip = aip ;
1074+
1075+ aip -> family = wg_aip -> a_af ;
1076+ if (wg_aip -> a_af == AF_INET ) {
1077+ memcpy (& aip -> ip4 , & wg_aip -> a_ipv4 , sizeof (aip -> ip4 ));
1078+ aip -> cidr = wg_aip -> a_mask ;
1079+ } else if (wg_aip -> a_af == AF_INET6 ) {
1080+ memcpy (& aip -> ip6 , & wg_aip -> a_ipv6 , sizeof (aip -> ip6 ));
1081+ aip -> cidr = wg_aip -> a_mask ;
1082+ }
1083+ }
1084+ }
1085+
1086+ * device = dev ;
1087+ free (wgdata .wgd_mem );
1088+ return 0 ;
1089+ }
1090+
1091+ static int kernel_set_device (struct wgdevice * dev )
1092+ {
1093+ struct wg_data_io wgdata ;
1094+ struct wg_interface_io wg_iface ;
1095+ struct wg_peer_io * wg_peer ;
1096+ struct wg_aip_io * wg_aip ;
1097+
1098+ struct wgpeer * peer ;
1099+ struct wgallowedip * aip ;
1100+
1101+ getsock ();
1102+
1103+ strlcpy (wgdata .wgd_name , dev -> name , sizeof (wgdata .wgd_name ));
1104+ wgdata .wgd_mem = & wg_iface ;
1105+
1106+ bzero (& wg_iface , sizeof (wg_iface ));
1107+
1108+ if (dev -> flags & WGDEVICE_HAS_PRIVATE_KEY ) {
1109+ memcpy (wg_iface .i_private , dev -> private_key , WG_KEY_SIZE );
1110+ wg_iface .i_flags |= WG_INTERFACE_HAS_PRIVATE ;
1111+ }
1112+
1113+ if (dev -> flags & WGDEVICE_HAS_LISTEN_PORT ) {
1114+ wg_iface .i_port = htons (dev -> listen_port );
1115+ wg_iface .i_flags |= WG_INTERFACE_HAS_PORT ;
1116+ }
1117+
1118+ if (dev -> flags & WGDEVICE_HAS_FWMARK ) {
1119+ wg_iface .i_rtable = dev -> fwmark ;
1120+ wg_iface .i_flags |= WG_INTERFACE_HAS_RTABLE ;
1121+ }
1122+
1123+ if (dev -> flags & WGDEVICE_REPLACE_PEERS )
1124+ wg_iface .i_flags |= WG_INTERFACE_REPLACE_PEERS ;
1125+
1126+ for_each_wgpeer (dev , peer ) {
1127+ if ((wg_peer = calloc (1 , sizeof (* wg_peer ))) == NULL )
1128+ return - errno ;
1129+
1130+ wg_peer -> p_flags = WG_PEER_HAS_PUBLIC ;
1131+ memcpy (wg_peer -> p_public , peer -> public_key , WG_KEY_SIZE );
1132+
1133+ if (peer -> flags & WGPEER_HAS_PRESHARED_KEY ) {
1134+ memcpy (wg_peer -> p_psk , peer -> preshared_key , WG_KEY_SIZE );
1135+ wg_peer -> p_flags |= WG_PEER_HAS_PSK ;
1136+ }
1137+
1138+ if (peer -> flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL ) {
1139+ wg_peer -> p_pka = peer -> persistent_keepalive_interval ;
1140+ wg_peer -> p_flags |= WG_PEER_HAS_PKA ;
1141+ }
1142+
1143+ if (peer -> endpoint .addr .sa_family == AF_INET ||
1144+ peer -> endpoint .addr .sa_family == AF_INET6 ) {
1145+ memcpy (& wg_peer -> p_sa , & peer -> endpoint .addr , peer -> endpoint .addr .sa_len );
1146+ wg_peer -> p_flags |= WG_PEER_HAS_SOCKADDR ;
1147+ }
1148+
1149+ if (peer -> flags & WGPEER_REPLACE_ALLOWEDIPS )
1150+ wg_peer -> p_flags |= WG_PEER_REPLACE_AIPS ;
1151+
1152+ if (peer -> flags & WGPEER_REMOVE_ME )
1153+ wg_peer -> p_flags |= WG_PEER_REMOVE ;
1154+
1155+ wg_peer -> p_next = wg_iface .i_peers ;
1156+ wg_iface .i_peers = wg_peer ;
1157+
1158+ for_each_wgallowedip (peer , aip ) {
1159+ if ((wg_aip = calloc (1 , sizeof (* wg_aip ))) == NULL )
1160+ return - errno ;
1161+
1162+ wg_aip -> a_af = aip -> family ;
1163+ wg_aip -> a_mask = aip -> cidr ;
1164+
1165+ if (aip -> family == AF_INET )
1166+ memcpy (& wg_aip -> a_ipv4 , & aip -> ip4 , sizeof (aip -> ip4 ));
1167+ else if (aip -> family == AF_INET6 )
1168+ memcpy (& wg_aip -> a_ipv6 , & aip -> ip6 , sizeof (aip -> ip6 ));
1169+ else
1170+ return -1 ;
1171+
1172+ wg_aip -> a_next = wg_peer -> p_aips ;
1173+ wg_peer -> p_aips = wg_aip ;
1174+ }
1175+ }
1176+
1177+ if (ioctl (s , SIOCSWG , (caddr_t )& wgdata ) == -1 )
1178+ return - errno ;
1179+
1180+ return 0 ;
1181+ }
1182+ #endif /* OpenBSD */
1183+
9251184/* first\0second\0third\0forth\0last\0\0 */
9261185char * ipc_list_devices (void )
9271186{
9281187 struct string_list list = { 0 };
9291188 int ret ;
9301189
931- #ifdef __linux__
1190+ #if defined( __linux__ ) || defined( __OpenBSD__ )
9321191 ret = kernel_get_wireguard_interfaces (& list );
9331192 if (ret < 0 )
9341193 goto cleanup ;
@@ -948,7 +1207,7 @@ char *ipc_list_devices(void)
9481207
9491208int ipc_get_device (struct wgdevice * * dev , const char * iface )
9501209{
951- #ifdef __linux__
1210+ #if defined( __linux__ ) || defined( __OpenBSD__ )
9521211 if (userspace_has_wireguard_interface (iface ))
9531212 return userspace_get_device (dev , iface );
9541213 return kernel_get_device (dev , iface );
@@ -959,7 +1218,7 @@ int ipc_get_device(struct wgdevice **dev, const char *iface)
9591218
9601219int ipc_set_device (struct wgdevice * dev )
9611220{
962- #ifdef __linux__
1221+ #if defined( __linux__ ) || defined( __OpenBSD__ )
9631222 if (userspace_has_wireguard_interface (dev -> name ))
9641223 return userspace_set_device (dev );
9651224 return kernel_set_device (dev );
0 commit comments