Files
2025-12-30 01:20:20 +00:00

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;
}