xref: /kvmtool/net/uip/dhcp.c (revision 0796825e08da408fba6614d8a135a264d37ef9fe)
1 #include "kvm/uip.h"
2 
3 #include <arpa/inet.h>
4 
5 #define EMPTY_ADDR "0.0.0.0"
6 
uip_dhcp_is_discovery(struct uip_dhcp * dhcp)7 static inline bool uip_dhcp_is_discovery(struct uip_dhcp *dhcp)
8 {
9 	return (dhcp->option[2] == UIP_DHCP_DISCOVER &&
10 		dhcp->option[1] == UIP_DHCP_TAG_MSG_TYPE_LEN &&
11 		dhcp->option[0] == UIP_DHCP_TAG_MSG_TYPE);
12 }
13 
uip_dhcp_is_request(struct uip_dhcp * dhcp)14 static inline bool uip_dhcp_is_request(struct uip_dhcp *dhcp)
15 {
16 	return (dhcp->option[2] == UIP_DHCP_REQUEST &&
17 		dhcp->option[1] == UIP_DHCP_TAG_MSG_TYPE_LEN &&
18 		dhcp->option[0] == UIP_DHCP_TAG_MSG_TYPE);
19 }
20 
uip_udp_is_dhcp(struct uip_udp * udp)21 bool uip_udp_is_dhcp(struct uip_udp *udp)
22 {
23 	struct uip_dhcp *dhcp;
24 
25 	if (ntohs(udp->sport) != UIP_DHCP_PORT_CLIENT ||
26 	    ntohs(udp->dport) != UIP_DHCP_PORT_SERVER)
27 		return false;
28 
29 	dhcp = (struct uip_dhcp *)udp;
30 
31 	if (ntohl(dhcp->magic_cookie) != UIP_DHCP_MAGIC_COOKIE)
32 		return false;
33 
34 	return true;
35 }
36 
uip_dhcp_get_dns(struct uip_info * info)37 int uip_dhcp_get_dns(struct uip_info *info)
38 {
39 	char key[256], val[256];
40 	struct in_addr addr;
41 	int ret = -1;
42 	int n = 0;
43 	FILE *fp;
44 	u32 ip;
45 
46 	fp = fopen("/etc/resolv.conf", "r");
47 	if (!fp)
48 		return ret;
49 
50 	while (!feof(fp)) {
51 		if (fscanf(fp, "%s %s\n", key, val) != 2)
52 			continue;
53 		if (strncmp("domain", key, 6) == 0)
54 			info->domain_name = strndup(val, UIP_DHCP_MAX_DOMAIN_NAME_LEN);
55 		else if (strncmp("nameserver", key, 10) == 0) {
56 			if (!inet_aton(val, &addr))
57 				continue;
58 			ip = ntohl(addr.s_addr);
59 			if (n < UIP_DHCP_MAX_DNS_SERVER_NR)
60 				info->dns_ip[n++] = ip;
61 			ret = 0;
62 		}
63 	}
64 
65 	fclose(fp);
66 	return ret;
67 }
68 
uip_dhcp_fill_option_name_and_server(struct uip_info * info,u8 * opt,int i)69 static int uip_dhcp_fill_option_name_and_server(struct uip_info *info, u8 *opt, int i)
70 {
71 	u8 domain_name_len;
72 	u32 *addr;
73 	int n;
74 
75 	if (info->domain_name) {
76 		domain_name_len	= strlen(info->domain_name);
77 		opt[i++]	= UIP_DHCP_TAG_DOMAIN_NAME;
78 		opt[i++]	= domain_name_len;
79 		memcpy(&opt[i], info->domain_name, domain_name_len);
80 		i		+= domain_name_len;
81 	}
82 
83 	for (n = 0; n < UIP_DHCP_MAX_DNS_SERVER_NR; n++) {
84 		if (info->dns_ip[n] == 0)
85 			continue;
86 		opt[i++]	= UIP_DHCP_TAG_DNS_SERVER;
87 		opt[i++]	= UIP_DHCP_TAG_DNS_SERVER_LEN;
88 		addr		= (u32 *)&opt[i];
89 		*addr		= htonl(info->dns_ip[n]);
90 		i		+= UIP_DHCP_TAG_DNS_SERVER_LEN;
91 	}
92 
93 	return i;
94 }
uip_dhcp_fill_option(struct uip_info * info,struct uip_dhcp * dhcp,int reply_msg_type)95 static int uip_dhcp_fill_option(struct uip_info *info, struct uip_dhcp *dhcp, int reply_msg_type)
96 {
97 	int i = 0;
98 	u32 *addr;
99 	u8 *opt;
100 
101 	opt		= dhcp->option;
102 
103 	opt[i++]	= UIP_DHCP_TAG_MSG_TYPE;
104 	opt[i++]	= UIP_DHCP_TAG_MSG_TYPE_LEN;
105 	opt[i++]	= reply_msg_type;
106 
107 	opt[i++]	= UIP_DHCP_TAG_SERVER_ID;
108 	opt[i++]	= UIP_DHCP_TAG_SERVER_ID_LEN;
109 	addr		= (u32 *)&opt[i];
110 	*addr		= htonl(info->host_ip);
111 	i		+= UIP_DHCP_TAG_SERVER_ID_LEN;
112 
113 	opt[i++]	= UIP_DHCP_TAG_LEASE_TIME;
114 	opt[i++]	= UIP_DHCP_TAG_LEASE_TIME_LEN;
115 	addr		= (u32 *)&opt[i];
116 	*addr		= htonl(UIP_DHCP_LEASE_TIME);
117 	i		+= UIP_DHCP_TAG_LEASE_TIME_LEN;
118 
119 	opt[i++]	= UIP_DHCP_TAG_SUBMASK;
120 	opt[i++]	= UIP_DHCP_TAG_SUBMASK_LEN;
121 	addr		= (u32 *)&opt[i];
122 	*addr		= htonl(info->guest_netmask);
123 	i		+= UIP_DHCP_TAG_SUBMASK_LEN;
124 
125 	opt[i++]	= UIP_DHCP_TAG_ROUTER;
126 	opt[i++]	= UIP_DHCP_TAG_ROUTER_LEN;
127 	addr		= (u32 *)&opt[i];
128 	*addr		= htonl(info->host_ip);
129 	i		+= UIP_DHCP_TAG_ROUTER_LEN;
130 
131 	opt[i++]	= UIP_DHCP_TAG_ROOT;
132 	opt[i++]	= strlen(EMPTY_ADDR);
133 	addr		= (u32 *)&opt[i];
134 	strcpy((void *) addr, EMPTY_ADDR);
135 	i		+= strlen(EMPTY_ADDR);
136 
137 	i 		= uip_dhcp_fill_option_name_and_server(info, opt, i);
138 
139 	opt[i++]	= UIP_DHCP_TAG_END;
140 
141 	return 0;
142 }
143 
uip_dhcp_make_pkg(struct uip_info * info,struct uip_udp_socket * sk,struct uip_buf * buf,u8 reply_msg_type)144 static int uip_dhcp_make_pkg(struct uip_info *info, struct uip_udp_socket *sk, struct uip_buf *buf, u8 reply_msg_type)
145 {
146 	struct uip_dhcp *dhcp;
147 
148 	dhcp		= (struct uip_dhcp *)buf->eth;
149 
150 	dhcp->msg_type	= 2;
151 	dhcp->client_ip	= 0;
152 	dhcp->your_ip	= htonl(info->guest_ip);
153 	dhcp->server_ip	= htonl(info->host_ip);
154 	dhcp->agent_ip	= 0;
155 
156 	uip_dhcp_fill_option(info, dhcp, reply_msg_type);
157 
158 	sk->sip		= htonl(info->guest_ip);
159 	sk->dip		= htonl(info->host_ip);
160 	sk->sport	= htons(UIP_DHCP_PORT_CLIENT);
161 	sk->dport	= htons(UIP_DHCP_PORT_SERVER);
162 
163 	return 0;
164 }
165 
uip_tx_do_ipv4_udp_dhcp(struct uip_tx_arg * arg)166 int uip_tx_do_ipv4_udp_dhcp(struct uip_tx_arg *arg)
167 {
168 	struct uip_udp_socket sk;
169 	struct uip_dhcp *dhcp;
170 	struct uip_info *info;
171 	struct uip_buf *buf;
172 	u8 reply_msg_type;
173 
174 	dhcp = (struct uip_dhcp *)arg->eth;
175 
176 	if (uip_dhcp_is_discovery(dhcp))
177 		reply_msg_type = UIP_DHCP_OFFER;
178 	else if (uip_dhcp_is_request(dhcp))
179 		reply_msg_type = UIP_DHCP_ACK;
180 	else
181 		return -1;
182 
183 	buf = uip_buf_clone(arg);
184 	info = arg->info;
185 
186 	/*
187 	 * Cook DHCP pkg
188 	 */
189 	uip_dhcp_make_pkg(info, &sk, buf, reply_msg_type);
190 
191 	/*
192 	 * Cook UDP pkg
193 	 */
194 	uip_udp_make_pkg(info, &sk, buf, NULL, UIP_DHCP_MAX_PAYLOAD_LEN);
195 
196 	/*
197 	 * Send data received from socket to guest
198 	 */
199 	uip_buf_set_used(info, buf);
200 
201 	return 0;
202 }
203 
uip_dhcp_exit(struct uip_info * info)204 void uip_dhcp_exit(struct uip_info *info)
205 {
206 	free(info->domain_name);
207 	info->domain_name = NULL;
208 }
209