xref: /kvmtool/net/uip/dhcp.c (revision 155c7f336cc8af8a0899139c0e6b9e97d2bd9311)
1 #include "kvm/uip.h"
2 
3 #include <arpa/inet.h>
4 
5 static inline bool uip_dhcp_is_discovery(struct uip_dhcp *dhcp)
6 {
7 	return (dhcp->option[2] == UIP_DHCP_DISCOVER &&
8 		dhcp->option[1] == UIP_DHCP_TAG_MSG_TYPE_LEN &&
9 		dhcp->option[0] == UIP_DHCP_TAG_MSG_TYPE);
10 }
11 
12 static inline bool uip_dhcp_is_request(struct uip_dhcp *dhcp)
13 {
14 	return (dhcp->option[2] == UIP_DHCP_REQUEST &&
15 		dhcp->option[1] == UIP_DHCP_TAG_MSG_TYPE_LEN &&
16 		dhcp->option[0] == UIP_DHCP_TAG_MSG_TYPE);
17 }
18 
19 bool uip_udp_is_dhcp(struct uip_udp *udp)
20 {
21 	struct uip_dhcp *dhcp;
22 
23 	if (ntohs(udp->sport) != UIP_DHCP_PORT_CLIENT ||
24 	    ntohs(udp->dport) != UIP_DHCP_PORT_SERVER)
25 		return false;
26 
27 	dhcp = (struct uip_dhcp *)udp;
28 
29 	if (ntohl(dhcp->magic_cookie) != UIP_DHCP_MAGIC_COOKIE)
30 		return false;
31 
32 	return true;
33 }
34 
35 int uip_dhcp_get_dns(struct uip_info *info)
36 {
37 	char key[256], val[256];
38 	struct in_addr addr;
39 	int ret = -1;
40 	int n = 0;
41 	FILE *fp;
42 	u32 ip;
43 
44 	fp = fopen("/etc/resolv.conf", "r");
45 	if (!fp)
46 		goto out;
47 
48 	while (!feof(fp)) {
49 		if (fscanf(fp, "%s %s\n", key, val) != 2)
50 			continue;
51 		if (strncmp("domain", key, 6) == 0)
52 			info->domain_name = strndup(val, UIP_DHCP_MAX_DOMAIN_NAME_LEN);
53 		else if (strncmp("nameserver", key, 10) == 0) {
54 			if (!inet_aton(val, &addr))
55 				continue;
56 			ip = ntohl(addr.s_addr);
57 			if (n < UIP_DHCP_MAX_DNS_SERVER_NR)
58 				info->dns_ip[n++] = ip;
59 			ret = 0;
60 		}
61 	}
62 
63 out:
64 	fclose(fp);
65 	return ret;
66 }
67 
68 static int uip_dhcp_fill_option_name_and_server(struct uip_info *info, u8 *opt, int i)
69 {
70 	u8 domain_name_len;
71 	u32 *addr;
72 	int n;
73 
74 	if (info->domain_name) {
75 		domain_name_len	= strlen(info->domain_name);
76 		opt[i++]	= UIP_DHCP_TAG_DOMAIN_NAME;
77 		opt[i++]	= domain_name_len;
78 		memcpy(&opt[i], info->domain_name, domain_name_len);
79 		i		+= domain_name_len;
80 	}
81 
82 	for (n = 0; n < UIP_DHCP_MAX_DNS_SERVER_NR; n++) {
83 		if (info->dns_ip[n] == 0)
84 			continue;
85 		opt[i++]	= UIP_DHCP_TAG_DNS_SERVER;
86 		opt[i++]	= UIP_DHCP_TAG_DNS_SERVER_LEN;
87 		addr		= (u32 *)&opt[i];
88 		*addr		= htonl(info->dns_ip[n]);
89 		i		+= UIP_DHCP_TAG_DNS_SERVER_LEN;
90 	}
91 
92 	return i;
93 }
94 static int uip_dhcp_fill_option(struct uip_info *info, struct uip_dhcp *dhcp, int reply_msg_type)
95 {
96 	int i = 0;
97 	u32 *addr;
98 	u8 *opt;
99 
100 	opt		= dhcp->option;
101 
102 	opt[i++]	= UIP_DHCP_TAG_MSG_TYPE;
103 	opt[i++]	= UIP_DHCP_TAG_MSG_TYPE_LEN;
104 	opt[i++]	= reply_msg_type;
105 
106 	opt[i++]	= UIP_DHCP_TAG_SERVER_ID;
107 	opt[i++]	= UIP_DHCP_TAG_SERVER_ID_LEN;
108 	addr		= (u32 *)&opt[i];
109 	*addr		= htonl(info->host_ip);
110 	i		+= UIP_DHCP_TAG_SERVER_ID_LEN;
111 
112 	opt[i++]	= UIP_DHCP_TAG_LEASE_TIME;
113 	opt[i++]	= UIP_DHCP_TAG_LEASE_TIME_LEN;
114 	addr		= (u32 *)&opt[i];
115 	*addr		= htonl(UIP_DHCP_LEASE_TIME);
116 	i		+= UIP_DHCP_TAG_LEASE_TIME_LEN;
117 
118 	opt[i++]	= UIP_DHCP_TAG_SUBMASK;
119 	opt[i++]	= UIP_DHCP_TAG_SUBMASK_LEN;
120 	addr		= (u32 *)&opt[i];
121 	*addr		= htonl(info->guest_netmask);
122 	i		+= UIP_DHCP_TAG_SUBMASK_LEN;
123 
124 	opt[i++]	= UIP_DHCP_TAG_ROUTER;
125 	opt[i++]	= UIP_DHCP_TAG_ROUTER_LEN;
126 	addr		= (u32 *)&opt[i];
127 	*addr		= htonl(info->host_ip);
128 	i		+= UIP_DHCP_TAG_ROUTER_LEN;
129 
130 	i 		= uip_dhcp_fill_option_name_and_server(info, opt, i);
131 
132 	opt[i++]	= UIP_DHCP_TAG_END;
133 
134 	return 0;
135 }
136 
137 static int uip_dhcp_make_pkg(struct uip_info *info, struct uip_udp_socket *sk, struct uip_buf *buf, u8 reply_msg_type)
138 {
139 	struct uip_dhcp *dhcp;
140 
141 	dhcp		= (struct uip_dhcp *)buf->eth;
142 
143 	dhcp->msg_type	= 2;
144 	dhcp->client_ip	= 0;
145 	dhcp->your_ip	= htonl(info->guest_ip);
146 	dhcp->server_ip	= htonl(info->host_ip);
147 	dhcp->agent_ip	= 0;
148 
149 	uip_dhcp_fill_option(info, dhcp, reply_msg_type);
150 
151 	sk->sip		= htonl(info->guest_ip);
152 	sk->dip		= htonl(info->host_ip);
153 	sk->sport	= htons(UIP_DHCP_PORT_CLIENT);
154 	sk->dport	= htons(UIP_DHCP_PORT_SERVER);
155 
156 	return 0;
157 }
158