#include #include #include #include #include #include #include #include "quicktun.h" void usage() { fputs("Usage: qtctl add [ dev NAME ] [ mode { ethernet | ip } ]\n" " [ local_address ADDRESS ] [ local_port PORT ]\n" " [ remote_address ADDRESS ] [ remote_port PORT ]\n" " [ remote_float ]\n" " qtctl del dev NAME\n", stderr); exit(2); } void add(int argc, char *argv[], struct nl_handle *sock, int family) { struct nl_msg *msg; struct nl_cb *cb; int p = 1; uint16_t mode = QUICKTUN_MODE_ETHERNET; char *tmp_charp; struct in_addr tmp_addr; unsigned long tmp_ul; msg = nlmsg_alloc(); genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_ECHO, QUICKTUN_CMD_CREATE_DEVICE, 1); while ((++p) < argc) { if (!strcmp(argv[p], "dev")) { if ((++p) >= argc) usage(); tmp_charp = strndup(argv[p], IFNAMSIZ - 1); nla_put_string(msg, QUICKTUN_A_IFNAME, tmp_charp); free(tmp_charp); } else if (!strcmp(argv[p], "mode")) { if ((++p) >= argc) usage(); if (!strcmp(argv[p], "ethernet")) mode = QUICKTUN_MODE_ETHERNET; else if (!strcmp(argv[p], "ip")) mode = QUICKTUN_MODE_IP; else usage(); } else if (!strcmp(argv[p], "local_address")) { if ((++p) >= argc) usage(); if (!(inet_aton(argv[p], &tmp_addr))) usage(); nla_put_u32(msg, QUICKTUN_A_LOCAL_ADDRESS, tmp_addr.s_addr); } else if (!strcmp(argv[p], "local_port")) { if ((++p) >= argc) usage(); tmp_ul = strtoul(argv[p], &tmp_charp, 10); if (*tmp_charp) usage(); nla_put_u16(msg, QUICKTUN_A_LOCAL_PORT, htons((short)tmp_ul)); } else if (!strcmp(argv[p], "remote_address")) { if ((++p) >= argc) usage(); if (!(inet_aton(argv[p], &tmp_addr))) usage(); nla_put_u32(msg, QUICKTUN_A_REMOTE_ADDRESS, tmp_addr.s_addr); } else if (!strcmp(argv[p], "remote_port")) { if ((++p) >= argc) usage(); tmp_ul = strtoul(argv[p], &tmp_charp, 10); if (*tmp_charp) usage(); nla_put_u16(msg, QUICKTUN_A_REMOTE_PORT, htons((short)tmp_ul)); } else if (!strcmp(argv[p], "remote_float")) { nla_put_flag(msg, QUICKTUN_A_REMOTE_FLOAT); } else usage(); } nla_put_u16(msg, QUICKTUN_A_MODE, mode); nl_send_auto_complete(sock, msg); nlmsg_free(msg); cb = nl_cb_alloc(NL_CB_DEFAULT); nl_cb_err(cb, NL_CB_DEBUG, NULL, NULL); nl_recvmsgs(sock, cb); } void del(int argc, char *argv[], struct nl_handle *sock, int family) { struct nl_msg *msg; struct nl_cb *cb; int p = 1; char *tmp_charp; int has_dev = 0; msg = nlmsg_alloc(); genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_ECHO, QUICKTUN_CMD_DELETE_DEVICE, 1); while ((++p) < argc) { if (!strcmp(argv[p], "dev")) { if ((++p) >= argc) usage(); if (has_dev) usage(); tmp_charp = strndup(argv[p], IFNAMSIZ - 1); nla_put_string(msg, QUICKTUN_A_IFNAME, tmp_charp); free(tmp_charp); has_dev = 1; } } if (!has_dev) usage(); nl_send_auto_complete(sock, msg); nlmsg_free(msg); cb = nl_cb_alloc(NL_CB_DEFAULT); nl_cb_err(cb, NL_CB_DEBUG, NULL, NULL); nl_recvmsgs(sock, cb); } int main(int argc, char *argv[]) { struct nl_handle *sock; int family; sock = nl_handle_alloc(); genl_connect(sock); family = genl_ctrl_resolve(sock, "quicktun"); if (argc < 2) usage(); if (!strcmp(argv[1], "add")) add(argc, argv, sock, family); else if (!strcmp(argv[1], "del")) del(argc, argv, sock, family); else usage(); return 0; }