#include #include #include #include #include #include #include #include #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 \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; }