1 #include "kvm/uip.h" 2 3 #include <arpa/inet.h> 4 5 #define EMPTY_ADDR "0.0.0.0" 6 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 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 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 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 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 } 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 strncpy((void *) addr, EMPTY_ADDR, strlen(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 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 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 204 void uip_dhcp_exit(struct uip_info *info) 205 { 206 free(info->domain_name); 207 info->domain_name = NULL; 208 } 209