mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-06-16 02:15:47 +00:00
241 lines
5.2 KiB
C
241 lines
5.2 KiB
C
#include "kvm/uip.h"
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#define EMPTY_ADDR "0.0.0.0"
|
|
|
|
static u8 *uip_get_option(struct uip_dhcp *dhcp, u8 match, int *olen)
|
|
{
|
|
u8 *opt_end = ((u8 *)dhcp) + ntohs(dhcp->udp.len);
|
|
u8 *opt = dhcp->option;
|
|
|
|
while (*opt != 0xFF) {
|
|
if (*opt == 0) {
|
|
opt++;
|
|
continue;
|
|
}
|
|
if (*opt == match) {
|
|
*olen = *++opt;
|
|
return ++opt;
|
|
}
|
|
opt += 2 + opt[1];
|
|
if (opt >= opt_end)
|
|
return NULL;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static bool uip_dhcp_is_discovery(struct uip_dhcp *dhcp)
|
|
{
|
|
int olen;
|
|
u8 * opt = uip_get_option(dhcp, UIP_DHCP_TAG_MSG_TYPE, &olen);
|
|
|
|
printf("Check discovery\n");
|
|
if (opt == NULL || olen != UIP_DHCP_TAG_MSG_TYPE_LEN)
|
|
return false;
|
|
if (*opt != UIP_DHCP_DISCOVER)
|
|
return false;
|
|
printf("Discovery\n");
|
|
return true;
|
|
}
|
|
|
|
static bool uip_dhcp_is_request(struct uip_dhcp *dhcp)
|
|
{
|
|
int olen;
|
|
u8 * opt = uip_get_option(dhcp, UIP_DHCP_TAG_MSG_TYPE, &olen);
|
|
printf("Check response\n");
|
|
if (opt == NULL || olen != UIP_DHCP_TAG_MSG_TYPE_LEN)
|
|
return false;
|
|
if (*opt != UIP_DHCP_REQUEST)
|
|
return false;
|
|
printf("Response\n");
|
|
return true;
|
|
}
|
|
|
|
|
|
bool uip_udp_is_dhcp(struct uip_udp *udp)
|
|
{
|
|
struct uip_dhcp *dhcp;
|
|
|
|
if (ntohs(udp->sport) != UIP_DHCP_PORT_CLIENT ||
|
|
ntohs(udp->dport) != UIP_DHCP_PORT_SERVER)
|
|
return false;
|
|
|
|
dhcp = (struct uip_dhcp *)udp;
|
|
|
|
if (ntohl(dhcp->magic_cookie) != UIP_DHCP_MAGIC_COOKIE)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
int uip_dhcp_get_dns(struct uip_info *info)
|
|
{
|
|
char key[256], val[256];
|
|
struct in_addr addr;
|
|
int ret = -1;
|
|
int n = 0;
|
|
FILE *fp;
|
|
u32 ip;
|
|
|
|
fp = fopen("/etc/resolv.conf", "r");
|
|
if (!fp)
|
|
return ret;
|
|
|
|
while (!feof(fp)) {
|
|
if (fscanf(fp, "%s %s\n", key, val) != 2)
|
|
continue;
|
|
if (strncmp("domain", key, 6) == 0)
|
|
info->domain_name = strndup(val, UIP_DHCP_MAX_DOMAIN_NAME_LEN);
|
|
else if (strncmp("nameserver", key, 10) == 0) {
|
|
if (!inet_aton(val, &addr))
|
|
continue;
|
|
ip = ntohl(addr.s_addr);
|
|
if (n < UIP_DHCP_MAX_DNS_SERVER_NR)
|
|
info->dns_ip[n++] = ip;
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
fclose(fp);
|
|
return ret;
|
|
}
|
|
|
|
static int uip_dhcp_fill_option_name_and_server(struct uip_info *info, u8 *opt, int i)
|
|
{
|
|
u8 domain_name_len;
|
|
u32 *addr;
|
|
int n;
|
|
|
|
if (info->domain_name) {
|
|
domain_name_len = strlen(info->domain_name);
|
|
opt[i++] = UIP_DHCP_TAG_DOMAIN_NAME;
|
|
opt[i++] = domain_name_len;
|
|
memcpy(&opt[i], info->domain_name, domain_name_len);
|
|
i += domain_name_len;
|
|
}
|
|
|
|
for (n = 0; n < UIP_DHCP_MAX_DNS_SERVER_NR; n++) {
|
|
if (info->dns_ip[n] == 0)
|
|
continue;
|
|
opt[i++] = UIP_DHCP_TAG_DNS_SERVER;
|
|
opt[i++] = UIP_DHCP_TAG_DNS_SERVER_LEN;
|
|
addr = (u32 *)&opt[i];
|
|
*addr = htonl(info->dns_ip[n]);
|
|
i += UIP_DHCP_TAG_DNS_SERVER_LEN;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
static int uip_dhcp_fill_option(struct uip_info *info, struct uip_dhcp *dhcp, int reply_msg_type)
|
|
{
|
|
int i = 0;
|
|
u32 *addr;
|
|
u8 *opt;
|
|
|
|
opt = dhcp->option;
|
|
|
|
opt[i++] = UIP_DHCP_TAG_MSG_TYPE;
|
|
opt[i++] = UIP_DHCP_TAG_MSG_TYPE_LEN;
|
|
opt[i++] = reply_msg_type;
|
|
|
|
opt[i++] = UIP_DHCP_TAG_SERVER_ID;
|
|
opt[i++] = UIP_DHCP_TAG_SERVER_ID_LEN;
|
|
addr = (u32 *)&opt[i];
|
|
*addr = htonl(info->host_ip);
|
|
i += UIP_DHCP_TAG_SERVER_ID_LEN;
|
|
|
|
opt[i++] = UIP_DHCP_TAG_LEASE_TIME;
|
|
opt[i++] = UIP_DHCP_TAG_LEASE_TIME_LEN;
|
|
addr = (u32 *)&opt[i];
|
|
*addr = htonl(UIP_DHCP_LEASE_TIME);
|
|
i += UIP_DHCP_TAG_LEASE_TIME_LEN;
|
|
|
|
opt[i++] = UIP_DHCP_TAG_SUBMASK;
|
|
opt[i++] = UIP_DHCP_TAG_SUBMASK_LEN;
|
|
addr = (u32 *)&opt[i];
|
|
*addr = htonl(info->guest_netmask);
|
|
i += UIP_DHCP_TAG_SUBMASK_LEN;
|
|
|
|
opt[i++] = UIP_DHCP_TAG_ROUTER;
|
|
opt[i++] = UIP_DHCP_TAG_ROUTER_LEN;
|
|
addr = (u32 *)&opt[i];
|
|
*addr = htonl(info->host_ip);
|
|
i += UIP_DHCP_TAG_ROUTER_LEN;
|
|
|
|
opt[i++] = UIP_DHCP_TAG_ROOT;
|
|
opt[i++] = strlen(EMPTY_ADDR);
|
|
addr = (u32 *)&opt[i];
|
|
strncpy((void *) addr, EMPTY_ADDR, strlen(EMPTY_ADDR));
|
|
i += strlen(EMPTY_ADDR);
|
|
|
|
i = uip_dhcp_fill_option_name_and_server(info, opt, i);
|
|
|
|
opt[i++] = UIP_DHCP_TAG_END;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int uip_dhcp_make_pkg(struct uip_info *info, struct uip_udp_socket *sk, struct uip_buf *buf, u8 reply_msg_type)
|
|
{
|
|
struct uip_dhcp *dhcp;
|
|
struct uip_ip *ip;
|
|
|
|
ip = (struct uip_ip *)buf->eth;
|
|
dhcp = (struct uip_dhcp *)(ip + 1);
|
|
dhcp->msg_type = 2;
|
|
dhcp->client_ip = 0;
|
|
dhcp->your_ip = htonl(info->guest_ip);
|
|
dhcp->server_ip = htonl(info->host_ip);
|
|
dhcp->agent_ip = 0;
|
|
|
|
uip_dhcp_fill_option(info, dhcp, reply_msg_type);
|
|
|
|
sk->sip = htonl(info->guest_ip);
|
|
sk->dip = htonl(info->host_ip);
|
|
sk->sport = htons(UIP_DHCP_PORT_CLIENT);
|
|
sk->dport = htons(UIP_DHCP_PORT_SERVER);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int uip_tx_do_ipv4_udp_dhcp(struct uip_tx_arg *arg)
|
|
{
|
|
struct uip_udp_socket sk;
|
|
struct uip_ip *ip;
|
|
struct uip_dhcp *dhcp;
|
|
struct uip_info *info;
|
|
struct uip_buf *buf;
|
|
u8 reply_msg_type;
|
|
|
|
ip = (struct uip_ip *)arg->eth;
|
|
dhcp = (struct uip_dhcp *)(((uint8_t *)ip) + uip_ip_hdrlen(ip) + 14); /* 14 is ethernet header */
|
|
|
|
if (uip_dhcp_is_discovery(dhcp))
|
|
reply_msg_type = UIP_DHCP_OFFER;
|
|
else if (uip_dhcp_is_request(dhcp))
|
|
reply_msg_type = UIP_DHCP_ACK;
|
|
else
|
|
return -1;
|
|
|
|
buf = uip_buf_clone(arg);
|
|
info = arg->info;
|
|
|
|
/*
|
|
* Cook DHCP pkg
|
|
*/
|
|
uip_dhcp_make_pkg(info, &sk, buf, reply_msg_type);
|
|
|
|
/*
|
|
* Cook UDP pkg
|
|
*/
|
|
uip_udp_make_pkg(info, &sk, buf, NULL, UIP_DHCP_MAX_PAYLOAD_LEN);
|
|
|
|
/*
|
|
* Send data received from socket to guest
|
|
*/
|
|
uip_buf_set_used(info, buf);
|
|
|
|
return 0;
|
|
}
|