1*fb81684fSAxel Dörfler /* 2*fb81684fSAxel Dörfler * Copyright 2006, Haiku, Inc. All Rights Reserved. 3*fb81684fSAxel Dörfler * Distributed under the terms of the MIT License. 4*fb81684fSAxel Dörfler * 5*fb81684fSAxel Dörfler * Authors: 6*fb81684fSAxel Dörfler * Axel Dörfler, axeld@pinc-software.de 7*fb81684fSAxel Dörfler */ 8*fb81684fSAxel Dörfler 9*fb81684fSAxel Dörfler 10*fb81684fSAxel Dörfler #include "DHCPClient.h" 11*fb81684fSAxel Dörfler #include "NetServer.h" 12*fb81684fSAxel Dörfler 13*fb81684fSAxel Dörfler #include <errno.h> 14*fb81684fSAxel Dörfler #include <netinet/in.h> 15*fb81684fSAxel Dörfler #include <stdio.h> 16*fb81684fSAxel Dörfler #include <string.h> 17*fb81684fSAxel Dörfler 18*fb81684fSAxel Dörfler 19*fb81684fSAxel Dörfler // See RFC 2131 for DHCP, see RFC 1533 for BOOTP/DHCP options 20*fb81684fSAxel Dörfler 21*fb81684fSAxel Dörfler #define DHCP_CLIENT_PORT 68 22*fb81684fSAxel Dörfler #define DHCP_SERVER_PORT 67 23*fb81684fSAxel Dörfler 24*fb81684fSAxel Dörfler enum message_opcode { 25*fb81684fSAxel Dörfler BOOT_REQUEST = 1, 26*fb81684fSAxel Dörfler BOOT_REPLY 27*fb81684fSAxel Dörfler }; 28*fb81684fSAxel Dörfler 29*fb81684fSAxel Dörfler enum message_option { 30*fb81684fSAxel Dörfler OPTION_MAGIC = 0x63825363, 31*fb81684fSAxel Dörfler 32*fb81684fSAxel Dörfler // generic options 33*fb81684fSAxel Dörfler OPTION_PAD = 0, 34*fb81684fSAxel Dörfler OPTION_END = 1, 35*fb81684fSAxel Dörfler OPTION_DATAGRAM_SIZE = 22, 36*fb81684fSAxel Dörfler OPTION_MTU = 26, 37*fb81684fSAxel Dörfler OPTION_BROADCAST_ADDRESS = 28, 38*fb81684fSAxel Dörfler OPTION_NETWORK_TIME_SERVERS = 42, 39*fb81684fSAxel Dörfler 40*fb81684fSAxel Dörfler // DHCP specific options 41*fb81684fSAxel Dörfler OPTION_REQUEST_IP_ADDRESS = 50, 42*fb81684fSAxel Dörfler OPTION_ADDRESS_LEASE_TIME = 51, 43*fb81684fSAxel Dörfler OPTION_OVERLOAD = 52, 44*fb81684fSAxel Dörfler OPTION_MESSAGE_TYPE = 53, 45*fb81684fSAxel Dörfler OPTION_SERVER_ADDRESS = 54, 46*fb81684fSAxel Dörfler OPTION_REQUEST_PARAMETERS = 55, 47*fb81684fSAxel Dörfler OPTION_ERROR_MESSAGE = 56, 48*fb81684fSAxel Dörfler OPTION_MESSAGE_SIZE = 57, 49*fb81684fSAxel Dörfler OPTION_RENEWAL_TIME = 58, 50*fb81684fSAxel Dörfler OPTION_REBINDING_TIME = 59, 51*fb81684fSAxel Dörfler OPTION_CLASS_IDENTIFIER = 60, 52*fb81684fSAxel Dörfler OPTION_CLIENT_IDENTIFIER = 61, 53*fb81684fSAxel Dörfler }; 54*fb81684fSAxel Dörfler 55*fb81684fSAxel Dörfler enum message_type { 56*fb81684fSAxel Dörfler DHCP_DISCOVER = 1, 57*fb81684fSAxel Dörfler DHCP_OFFER, 58*fb81684fSAxel Dörfler DHCP_REQUEST, 59*fb81684fSAxel Dörfler DHCP_DECLINE, 60*fb81684fSAxel Dörfler DHCP_ACK, 61*fb81684fSAxel Dörfler DHCP_NAK, 62*fb81684fSAxel Dörfler DHCP_RELEASE, 63*fb81684fSAxel Dörfler DHCP_INFORM 64*fb81684fSAxel Dörfler }; 65*fb81684fSAxel Dörfler 66*fb81684fSAxel Dörfler struct dhcp_option_cookie { 67*fb81684fSAxel Dörfler dhcp_option_cookie() : state(0), file_has_options(false), server_name_has_options(false) {} 68*fb81684fSAxel Dörfler 69*fb81684fSAxel Dörfler const uint8* next; 70*fb81684fSAxel Dörfler uint8 state; 71*fb81684fSAxel Dörfler bool file_has_options; 72*fb81684fSAxel Dörfler bool server_name_has_options; 73*fb81684fSAxel Dörfler }; 74*fb81684fSAxel Dörfler 75*fb81684fSAxel Dörfler struct dhcp_message { 76*fb81684fSAxel Dörfler dhcp_message(message_type type); 77*fb81684fSAxel Dörfler 78*fb81684fSAxel Dörfler uint8 opcode; 79*fb81684fSAxel Dörfler uint8 hardware_type; 80*fb81684fSAxel Dörfler uint8 hardware_address_length; 81*fb81684fSAxel Dörfler uint8 hop_count; 82*fb81684fSAxel Dörfler uint32 transaction_id; 83*fb81684fSAxel Dörfler uint16 seconds_since_boot; 84*fb81684fSAxel Dörfler uint16 flags; 85*fb81684fSAxel Dörfler in_addr_t client_address; 86*fb81684fSAxel Dörfler in_addr_t your_address; 87*fb81684fSAxel Dörfler in_addr_t server_address; 88*fb81684fSAxel Dörfler in_addr_t gateway_address; 89*fb81684fSAxel Dörfler uint8 mac_address[16]; 90*fb81684fSAxel Dörfler uint8 server_name[64]; 91*fb81684fSAxel Dörfler uint8 file[128]; 92*fb81684fSAxel Dörfler uint32 options_magic; 93*fb81684fSAxel Dörfler uint8 options[1260]; 94*fb81684fSAxel Dörfler 95*fb81684fSAxel Dörfler size_t MinSize() const { return 576; } 96*fb81684fSAxel Dörfler size_t Size() const; 97*fb81684fSAxel Dörfler 98*fb81684fSAxel Dörfler bool HasOptions() const; 99*fb81684fSAxel Dörfler bool NextOption(dhcp_option_cookie& cookie, message_option& option, 100*fb81684fSAxel Dörfler const uint8*& data, size_t& size) const; 101*fb81684fSAxel Dörfler const uint8* LastOption() const; 102*fb81684fSAxel Dörfler 103*fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option); 104*fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint8 data); 105*fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint16 data); 106*fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint32 data); 107*fb81684fSAxel Dörfler uint8* PutOption(uint8* options, message_option option, uint8* data, uint32 size); 108*fb81684fSAxel Dörfler } _PACKED; 109*fb81684fSAxel Dörfler 110*fb81684fSAxel Dörfler 111*fb81684fSAxel Dörfler #define ARP_HARDWARE_TYPE_ETHER 1 112*fb81684fSAxel Dörfler 113*fb81684fSAxel Dörfler 114*fb81684fSAxel Dörfler dhcp_message::dhcp_message(message_type type) 115*fb81684fSAxel Dörfler { 116*fb81684fSAxel Dörfler memset(this, 0, sizeof(*this)); 117*fb81684fSAxel Dörfler options_magic = htonl(OPTION_MAGIC); 118*fb81684fSAxel Dörfler 119*fb81684fSAxel Dörfler uint8* next = options; 120*fb81684fSAxel Dörfler next = PutOption(next, OPTION_MESSAGE_TYPE, (uint8)type); 121*fb81684fSAxel Dörfler next = PutOption(next, OPTION_MESSAGE_SIZE, (uint16)sizeof(dhcp_message)); 122*fb81684fSAxel Dörfler next = PutOption(next, OPTION_END); 123*fb81684fSAxel Dörfler } 124*fb81684fSAxel Dörfler 125*fb81684fSAxel Dörfler 126*fb81684fSAxel Dörfler bool 127*fb81684fSAxel Dörfler dhcp_message::HasOptions() const 128*fb81684fSAxel Dörfler { 129*fb81684fSAxel Dörfler return options_magic == htonl(OPTION_MAGIC); 130*fb81684fSAxel Dörfler } 131*fb81684fSAxel Dörfler 132*fb81684fSAxel Dörfler 133*fb81684fSAxel Dörfler bool 134*fb81684fSAxel Dörfler dhcp_message::NextOption(dhcp_option_cookie& cookie, 135*fb81684fSAxel Dörfler message_option& option, const uint8*& data, size_t& size) const 136*fb81684fSAxel Dörfler { 137*fb81684fSAxel Dörfler if (cookie.state == 0) { 138*fb81684fSAxel Dörfler if (!HasOptions()) 139*fb81684fSAxel Dörfler return false; 140*fb81684fSAxel Dörfler 141*fb81684fSAxel Dörfler cookie.state++; 142*fb81684fSAxel Dörfler cookie.next = options; 143*fb81684fSAxel Dörfler } 144*fb81684fSAxel Dörfler 145*fb81684fSAxel Dörfler uint32 bytesLeft = 0; 146*fb81684fSAxel Dörfler 147*fb81684fSAxel Dörfler switch (cookie.state) { 148*fb81684fSAxel Dörfler case 1: 149*fb81684fSAxel Dörfler // options from "options" 150*fb81684fSAxel Dörfler bytesLeft = sizeof(options) + cookie.next - options; 151*fb81684fSAxel Dörfler break; 152*fb81684fSAxel Dörfler 153*fb81684fSAxel Dörfler case 2: 154*fb81684fSAxel Dörfler // options from "file" 155*fb81684fSAxel Dörfler bytesLeft = sizeof(options) + cookie.next - options; 156*fb81684fSAxel Dörfler break; 157*fb81684fSAxel Dörfler 158*fb81684fSAxel Dörfler case 3: 159*fb81684fSAxel Dörfler // options from "server_name" 160*fb81684fSAxel Dörfler bytesLeft = sizeof(options) + cookie.next - options; 161*fb81684fSAxel Dörfler break; 162*fb81684fSAxel Dörfler } 163*fb81684fSAxel Dörfler 164*fb81684fSAxel Dörfler while (true) { 165*fb81684fSAxel Dörfler if (bytesLeft == 0) { 166*fb81684fSAxel Dörfler // TODO: suppport OPTION_OVERLOAD! 167*fb81684fSAxel Dörfler cookie.state = 4; 168*fb81684fSAxel Dörfler return false; 169*fb81684fSAxel Dörfler } 170*fb81684fSAxel Dörfler 171*fb81684fSAxel Dörfler option = (message_option)cookie.next[0]; 172*fb81684fSAxel Dörfler if (option == OPTION_END) { 173*fb81684fSAxel Dörfler cookie.state = 4; 174*fb81684fSAxel Dörfler return false; 175*fb81684fSAxel Dörfler } else if (option == OPTION_PAD) { 176*fb81684fSAxel Dörfler bytesLeft--; 177*fb81684fSAxel Dörfler cookie.next++; 178*fb81684fSAxel Dörfler continue; 179*fb81684fSAxel Dörfler } 180*fb81684fSAxel Dörfler 181*fb81684fSAxel Dörfler size = cookie.next[1]; 182*fb81684fSAxel Dörfler data = &cookie.next[2]; 183*fb81684fSAxel Dörfler cookie.next += 2 + size; 184*fb81684fSAxel Dörfler 185*fb81684fSAxel Dörfler if (option == OPTION_OVERLOAD) { 186*fb81684fSAxel Dörfler cookie.file_has_options = data[0] & 1; 187*fb81684fSAxel Dörfler cookie.server_name_has_options = data[0] & 2; 188*fb81684fSAxel Dörfler continue; 189*fb81684fSAxel Dörfler } 190*fb81684fSAxel Dörfler 191*fb81684fSAxel Dörfler return true; 192*fb81684fSAxel Dörfler } 193*fb81684fSAxel Dörfler } 194*fb81684fSAxel Dörfler 195*fb81684fSAxel Dörfler 196*fb81684fSAxel Dörfler const uint8* 197*fb81684fSAxel Dörfler dhcp_message::LastOption() const 198*fb81684fSAxel Dörfler { 199*fb81684fSAxel Dörfler dhcp_option_cookie cookie; 200*fb81684fSAxel Dörfler message_option option; 201*fb81684fSAxel Dörfler const uint8 *data; 202*fb81684fSAxel Dörfler size_t size; 203*fb81684fSAxel Dörfler while (NextOption(cookie, option, data, size)) { 204*fb81684fSAxel Dörfler // iterate through all options 205*fb81684fSAxel Dörfler } 206*fb81684fSAxel Dörfler 207*fb81684fSAxel Dörfler return cookie.next; 208*fb81684fSAxel Dörfler } 209*fb81684fSAxel Dörfler 210*fb81684fSAxel Dörfler 211*fb81684fSAxel Dörfler size_t 212*fb81684fSAxel Dörfler dhcp_message::Size() const 213*fb81684fSAxel Dörfler { 214*fb81684fSAxel Dörfler const uint8* last = LastOption(); 215*fb81684fSAxel Dörfler return sizeof(dhcp_message) - sizeof(options) + last + 1 - options; 216*fb81684fSAxel Dörfler } 217*fb81684fSAxel Dörfler 218*fb81684fSAxel Dörfler 219*fb81684fSAxel Dörfler uint8* 220*fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option) 221*fb81684fSAxel Dörfler { 222*fb81684fSAxel Dörfler options[0] = option; 223*fb81684fSAxel Dörfler return options + 1; 224*fb81684fSAxel Dörfler } 225*fb81684fSAxel Dörfler 226*fb81684fSAxel Dörfler 227*fb81684fSAxel Dörfler uint8* 228*fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint8 data) 229*fb81684fSAxel Dörfler { 230*fb81684fSAxel Dörfler return PutOption(options, option, &data, 1); 231*fb81684fSAxel Dörfler } 232*fb81684fSAxel Dörfler 233*fb81684fSAxel Dörfler 234*fb81684fSAxel Dörfler uint8* 235*fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint16 data) 236*fb81684fSAxel Dörfler { 237*fb81684fSAxel Dörfler data = htons(data); 238*fb81684fSAxel Dörfler return PutOption(options, option, (uint8*)&data, sizeof(data)); 239*fb81684fSAxel Dörfler } 240*fb81684fSAxel Dörfler 241*fb81684fSAxel Dörfler 242*fb81684fSAxel Dörfler uint8* 243*fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint32 data) 244*fb81684fSAxel Dörfler { 245*fb81684fSAxel Dörfler data = htonl(data); 246*fb81684fSAxel Dörfler return PutOption(options, option, (uint8*)&data, sizeof(data)); 247*fb81684fSAxel Dörfler } 248*fb81684fSAxel Dörfler 249*fb81684fSAxel Dörfler 250*fb81684fSAxel Dörfler uint8* 251*fb81684fSAxel Dörfler dhcp_message::PutOption(uint8* options, message_option option, uint8* data, uint32 size) 252*fb81684fSAxel Dörfler { 253*fb81684fSAxel Dörfler options[0] = option; 254*fb81684fSAxel Dörfler options[1] = size; 255*fb81684fSAxel Dörfler memcpy(&options[2], data, size); 256*fb81684fSAxel Dörfler 257*fb81684fSAxel Dörfler return options + 2 + size; 258*fb81684fSAxel Dörfler } 259*fb81684fSAxel Dörfler 260*fb81684fSAxel Dörfler 261*fb81684fSAxel Dörfler // #pragma mark - 262*fb81684fSAxel Dörfler 263*fb81684fSAxel Dörfler 264*fb81684fSAxel Dörfler DHCPClient::DHCPClient(const char* device) 265*fb81684fSAxel Dörfler : BHandler("dhcp"), 266*fb81684fSAxel Dörfler fDevice(device) 267*fb81684fSAxel Dörfler { 268*fb81684fSAxel Dörfler fTransactionID = system_time(); 269*fb81684fSAxel Dörfler 270*fb81684fSAxel Dörfler dhcp_message message(DHCP_DISCOVER); 271*fb81684fSAxel Dörfler message.opcode = BOOT_REQUEST; 272*fb81684fSAxel Dörfler message.hardware_type = ARP_HARDWARE_TYPE_ETHER; 273*fb81684fSAxel Dörfler message.hardware_address_length = 6; 274*fb81684fSAxel Dörfler message.transaction_id = htonl(fTransactionID); 275*fb81684fSAxel Dörfler message.seconds_since_boot = htons(max_c(system_time() / 1000000LL, 65535)); 276*fb81684fSAxel Dörfler fStatus = get_mac_address(device, message.mac_address); 277*fb81684fSAxel Dörfler if (fStatus < B_OK) 278*fb81684fSAxel Dörfler return; 279*fb81684fSAxel Dörfler 280*fb81684fSAxel Dörfler int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 281*fb81684fSAxel Dörfler if (socket < 0) { 282*fb81684fSAxel Dörfler fStatus = errno; 283*fb81684fSAxel Dörfler return; 284*fb81684fSAxel Dörfler } 285*fb81684fSAxel Dörfler 286*fb81684fSAxel Dörfler sockaddr_in local; 287*fb81684fSAxel Dörfler memset(&local, 0, sizeof(struct sockaddr_in)); 288*fb81684fSAxel Dörfler local.sin_family = AF_INET; 289*fb81684fSAxel Dörfler local.sin_len = sizeof(struct sockaddr_in); 290*fb81684fSAxel Dörfler local.sin_port = htons(DHCP_CLIENT_PORT); 291*fb81684fSAxel Dörfler local.sin_addr.s_addr = INADDR_ANY; 292*fb81684fSAxel Dörfler 293*fb81684fSAxel Dörfler if (bind(socket, (struct sockaddr *)&local, sizeof(local)) < 0) { 294*fb81684fSAxel Dörfler fStatus = errno; 295*fb81684fSAxel Dörfler close(socket); 296*fb81684fSAxel Dörfler return; 297*fb81684fSAxel Dörfler } 298*fb81684fSAxel Dörfler 299*fb81684fSAxel Dörfler sockaddr_in broadcast; 300*fb81684fSAxel Dörfler memset(&broadcast, 0, sizeof(struct sockaddr_in)); 301*fb81684fSAxel Dörfler broadcast.sin_family = AF_INET; 302*fb81684fSAxel Dörfler broadcast.sin_len = sizeof(struct sockaddr_in); 303*fb81684fSAxel Dörfler broadcast.sin_port = htons(DHCP_SERVER_PORT); 304*fb81684fSAxel Dörfler broadcast.sin_addr.s_addr = INADDR_BROADCAST; 305*fb81684fSAxel Dörfler 306*fb81684fSAxel Dörfler int option = 1; 307*fb81684fSAxel Dörfler setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option)); 308*fb81684fSAxel Dörfler 309*fb81684fSAxel Dörfler printf("DHCP message size %lu\n", message.Size()); 310*fb81684fSAxel Dörfler 311*fb81684fSAxel Dörfler ssize_t bytesSent = sendto(socket, &message, message.MinSize(), 0, 312*fb81684fSAxel Dörfler (struct sockaddr*)&broadcast, sizeof(broadcast)); 313*fb81684fSAxel Dörfler if (bytesSent < 0) { 314*fb81684fSAxel Dörfler fStatus = errno; 315*fb81684fSAxel Dörfler close(socket); 316*fb81684fSAxel Dörfler return; 317*fb81684fSAxel Dörfler } 318*fb81684fSAxel Dörfler 319*fb81684fSAxel Dörfler close(socket); 320*fb81684fSAxel Dörfler fStatus = B_ERROR; 321*fb81684fSAxel Dörfler } 322*fb81684fSAxel Dörfler 323*fb81684fSAxel Dörfler 324*fb81684fSAxel Dörfler DHCPClient::~DHCPClient() 325*fb81684fSAxel Dörfler { 326*fb81684fSAxel Dörfler } 327*fb81684fSAxel Dörfler 328*fb81684fSAxel Dörfler 329*fb81684fSAxel Dörfler status_t 330*fb81684fSAxel Dörfler DHCPClient::InitCheck() 331*fb81684fSAxel Dörfler { 332*fb81684fSAxel Dörfler printf("DHCP for %s, status: %s\n", fDevice.String(), strerror(fStatus)); 333*fb81684fSAxel Dörfler return fStatus; 334*fb81684fSAxel Dörfler } 335*fb81684fSAxel Dörfler 336*fb81684fSAxel Dörfler 337*fb81684fSAxel Dörfler void 338*fb81684fSAxel Dörfler DHCPClient::MessageReceived(BMessage* message) 339*fb81684fSAxel Dörfler { 340*fb81684fSAxel Dörfler BHandler::MessageReceived(message); 341*fb81684fSAxel Dörfler } 342*fb81684fSAxel Dörfler 343