125 lines
3.8 KiB
C
125 lines
3.8 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/socket.h>
|
|
#include <linux/netlink.h>
|
|
#include <linux/rtnetlink.h>
|
|
#include <errno.h>
|
|
|
|
#define BUF_SIZE 4096
|
|
|
|
// 요청 메시지 구조체 (패딩 문제 방지를 위해 바이트 배열로 관리)
|
|
struct req_t {
|
|
struct nlmsghdr n;
|
|
char buf[BUF_SIZE];
|
|
};
|
|
|
|
// 속성 추가 (RTA_APPEND)
|
|
// 커널의 표준 방식대로 테일 포인터를 이동시키며 추가
|
|
int addattr_l(struct req_t *req, int type, const void *data, int alen) {
|
|
int len = RTA_LENGTH(alen);
|
|
struct rtattr *rta;
|
|
|
|
// 현재 메시지 길이 (헤더 포함)
|
|
int msg_len = req->n.nlmsg_len;
|
|
|
|
if (NLMSG_ALIGN(msg_len) + RTA_ALIGN(len) > sizeof(struct req_t)) {
|
|
fprintf(stderr, "addattr_l: Message too long\n");
|
|
return -1;
|
|
}
|
|
|
|
// 데이터가 들어갈 위치 계산
|
|
rta = (struct rtattr *)(((char *)&req->n) + NLMSG_ALIGN(msg_len));
|
|
rta->rta_type = type;
|
|
rta->rta_len = len;
|
|
|
|
if (alen) {
|
|
memcpy(RTA_DATA(rta), data, alen);
|
|
}
|
|
|
|
// 메시지 전체 길이 업데이트
|
|
req->n.nlmsg_len = NLMSG_ALIGN(msg_len) + RTA_ALIGN(len);
|
|
return 0;
|
|
}
|
|
|
|
// 중첩 속성 시작 (Nested Start)
|
|
struct rtattr *addattr_nest(struct req_t *req, int type) {
|
|
struct rtattr *nest = (struct rtattr *)(((char *)&req->n) + NLMSG_ALIGN(req->n.nlmsg_len));
|
|
|
|
// 빈 속성 추가 (일단 데이터 없이)
|
|
if (addattr_l(req, type, NULL, 0) < 0) return NULL;
|
|
|
|
return nest;
|
|
}
|
|
|
|
// 중첩 속성 끝 (Nested End)
|
|
void addattr_nest_end(struct req_t *req, struct rtattr *nest) {
|
|
// 중첩 속성의 길이는 (현재 전체 길이) - (중첩 속성 시작 위치)
|
|
nest->rta_len = (char *)&req->n + req->n.nlmsg_len - (char *)nest;
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
if (argc != 3 || strcmp(argv[1], "create") != 0) {
|
|
printf("Usage: wg create <interface_name>\n");
|
|
return 1;
|
|
}
|
|
|
|
char *ifname = argv[2];
|
|
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
|
if (fd < 0) { perror("socket"); return 1; }
|
|
|
|
struct req_t req;
|
|
memset(&req, 0, sizeof(req));
|
|
|
|
// 1. 헤더 설정
|
|
// 초기 길이는 헤더 + ifinfomsg 구조체 크기
|
|
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
|
req.n.nlmsg_type = RTM_NEWLINK;
|
|
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
|
|
|
|
struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(&req.n);
|
|
ifi->ifi_family = AF_UNSPEC;
|
|
|
|
// 2. IFLA_IFNAME: 인터페이스 이름 ("wg0")
|
|
// 문자열은 반드시 NULL 문자 포함 길이 (+1)
|
|
addattr_l(&req, IFLA_IFNAME, ifname, strlen(ifname) + 1);
|
|
|
|
// 3. IFLA_LINKINFO: 링크 정보 시작
|
|
struct rtattr *linkinfo = addattr_nest(&req, IFLA_LINKINFO);
|
|
|
|
// 4. IFLA_INFO_KIND: 타입 ("wireguard")
|
|
addattr_l(&req, IFLA_INFO_KIND, "wireguard", strlen("wireguard") + 1);
|
|
|
|
// 링크 정보 종료
|
|
addattr_nest_end(&req, linkinfo);
|
|
|
|
// 디버깅: 전송할 패킷 크기 출력
|
|
// printf("Sending Netlink Msg: %d bytes\n", req.n.nlmsg_len);
|
|
|
|
// 5. 전송
|
|
if (send(fd, &req.n, req.n.nlmsg_len, 0) < 0) {
|
|
perror("send");
|
|
close(fd);
|
|
return 1;
|
|
}
|
|
|
|
// 6. 응답 수신
|
|
char buf[BUF_SIZE];
|
|
int len = recv(fd, buf, sizeof(buf), 0);
|
|
if (len < 0) { perror("recv"); return 1; }
|
|
|
|
struct nlmsghdr *nh = (struct nlmsghdr *)buf;
|
|
if (nh->nlmsg_type == NLMSG_ERROR) {
|
|
struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(nh);
|
|
if (err->error == 0) {
|
|
printf("WireGuard interface '%s' created successfully!\n", ifname);
|
|
} else {
|
|
fprintf(stderr, "RTNETLINK error: %s (%d)\n", strerror(-err->error), -err->error);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
close(fd);
|
|
return 0;
|
|
} |