📄 server.c
字号:
#include "stdhead.h"#include "lib.h"#include "advertise.h"#include "reply.h"#include "parse.h"#include "leases.h"// Global state of the serverstruct config_head **subnet_conf; // Configuration for each subnetstruct lease_details *partial_lease; // Partial lease data structurestruct lease_details *lease; // Lease data structureint subnet_count; // Number of subnetsstruct DUID *server_duid; // Server's duidvoid quit (int signo){ exit (1);}int main (int argc, char **argv){ int listening_socket; // Listening socket for server int sending_socket; // Socket to send replies to clients struct sockaddr_in6 server_address; // Server socket address struct sockaddr_in6 client_address; // Client socket address char udp_message[MIN_MESSAGE_SIZE]; // UDP message buffer socklen_t cl = sizeof (client_address);// Client address's length // Local variables int i, result, message_len; char name[64]; fd_set testfds, readfds; struct timeval timeout; struct DHCP_MESSAGE *message, *sending_message; struct OPTIONS *opt_ptr; struct IA *ia_ptr; struct addr_details available_addr; // Setup a signal handler for Ctrl-C (quit) signal (SIGINT, quit); // Initialize listening socket write_to_log ("Initializing listening socket ...", 1); listening_socket = socket (PF_INET6, SOCK_DGRAM, 0); INITIALIZE_SOCKADDR (server_address); server_address.sin6_port = htons (AGENT_PORT); server_address.sin6_addr = in6addr_any; // Initialize sending socket write_to_log ("Initializing sending socket ...", 1); sending_socket = socket (PF_INET6, SOCK_DGRAM, 0); // Join dhcpv6 multicast groups write_to_log ("Joining multicast group ... ", 1); result = mcast_join (listening_socket, "eth0", ALL_DHCP_AGENTS); if (result == -1) { printf ("Server could not join ALL_DHCP_AGENTS multicast group\n"); exit (1); } result = mcast_join (listening_socket, "eth0", ALL_DHCP_SERVERS); if (result == -1) { printf ("Server could not join ALL_DHCP_SERVERS multicast group\n"); exit (1); } // Bind the listening socket to the server address write_to_log ("Binding listening socket to server address ...", 1); result = bind (listening_socket, (struct sockaddr *) &server_address, sizeof (server_address)); if (result == -1) { printf ("Server could not bind to agent port\n"); exit (1); } // Read server configuration file // check getopt(3) manual page for parsing command line options/* for (i = 0; i < argc; i++) if (!strcmp (argv[i], "--conf")) break; if (i < argc)*/ write_to_log ("Reading server configuration file ...", 1); subnet_conf = parse_and_assign (NULL, &subnet_count, 0); #if DEBUG == 1 printf ("Server configuration file was parsed\n");#elif DEBUG == 2 print_config_list_contents (subnet_conf[0]); print_server_duid();#endif // Open leases files write_to_log ("Reading leases and partial leases ...", 1); lease = read_leases_file (LEASES_FILE); partial_lease = read_leases_file (PARTIAL_LEASES_FILE); // Check for expired nodes in partial lease structure write_to_log ("Checking for and discarding expired nodes in partial leases ...", 1); remove_expired_nodes_from_partial_lease(); // Check for expired nodes in lease structure write_to_log ("Checking for expired nodes in leases ...", 1); check_leases_for_expiry(); // Dump leases structures to files write_to_log ("Dumping back leases and partial leases ...", 1); write_leases_file (LEASES_FILE, lease); write_leases_file (PARTIAL_LEASES_FILE, partial_lease);#if DEBUG == 1 printf ("Server about to enter select function\n");#endif // Add the listening socket to the select function's file descriptor set FD_ZERO (&readfds); FD_SET (listening_socket, &readfds); write_to_log ("\n\n\n-------------------------------------------------\n\n\n", 0); while (1) { testfds = readfds; // Set timeout to check expiry of leases timeout.tv_sec = FIVE_MINUTES; // Check for expired nodes in partial lease structure write_to_log ("Checking for and discarding expired nodes in partial leases ...", 1); remove_expired_nodes_from_partial_lease(); // Check for expired nodes in lease structure write_to_log ("Checking for expired nodes in leases ...", 1); check_leases_for_expiry(); // Dump leases structures to files write_to_log ("Dumping back leases and partial leases ...", 1); write_leases_file (LEASES_FILE, lease); write_leases_file (PARTIAL_LEASES_FILE, partial_lease); // Wait for activity on the socket select (listening_socket + 1, &testfds, 0, 0, &timeout); if (FD_ISSET (listening_socket, &testfds)) { // Receive message from client message_len = recvfrom (listening_socket, udp_message, MIN_MESSAGE_SIZE, 0, (struct sockaddr *) &client_address, &cl); // Change client address port for the purpose of sending back a reply client_address.sin6_port = htons (CLIENT_PORT); message = (struct DHCP_MESSAGE *) malloc (sizeof (struct DHCP_MESSAGE)); build_linked_list (udp_message, message_len, message); sending_message = 0;#if DEBUG == 1 printf ("Message type %d received from client with link - local address %s\n", message -> u_msg_type.msg_type, inet_ntop (AF_INET6, &client_address.sin6_addr.s6_addr, name, 64));#elif DEBUG == 2 print_linked_list_contents (message);#endif switch (message -> u_msg_type.msg_type) { case SOLICIT : write_to_log ("Solicit message received from ", 1); write_to_log ((char *) inet_ntop (AF_INET6, &client_address.sin6_addr.s6_addr, name, 64), 0); // Check for validity of solicit message if (!check_message (message, SOLICIT)) { write_to_log ("Solicit message received is invalid. Discarding ...", 1); break; } write_to_log ("Solicit message received is valid.", 1); // Check for duplicate solicit message if (check_for_duplicate_packet (message)) { write_to_log ("Solicit message received is duplicate. Discarding ...", 1); break; } // Check if preferred address available or not if (get_pref_address (&available_addr, partial_lease, lease, subnet_conf[0], client_address, get_options_ptr (message, OPTION_IAADDR))) { // send advertise message write_to_log ("Constructing advertise message with preferred IPv6 address...", 1); sending_message = create_advertise_message (message, &available_addr); // Add to partial lease structure write_to_log ("Adding node to partial leases ...", 1); add_node_to_partial_lease_structure (sending_message, &available_addr); } // Obtain the next available address else if (get_available_address (&available_addr, partial_lease, lease, subnet_conf[0], client_address)) { // send advertise message write_to_log ("Constructing advertise message with next available IPv6 address...", 1); sending_message = create_advertise_message (message, &available_addr); // Add to partial lease structure write_to_log ("Adding node to partial leases ...", 1); add_node_to_partial_lease_structure (sending_message, &available_addr); } else { // send advertise message with status code option as AddrUnavailable write_to_log ("Constructing advertise message with Address Unavailable status code...", 1); sending_message = create_message_with_status_code (message, ADVERTISE, Success, "Address Unavailable"); } break; case REQUEST : write_to_log ("Request message received.", 1); // Check for validity of request message if (!check_message (message, REQUEST)) { write_to_log ("Request message received is invalid. Discarding ...", 1); break; } // Check for duplicate request message if (check_for_duplicate_packet (message)) { write_to_log ("Request message received is duplicate. Discarding ...", 1); break; } // Create reply message write_to_log ("Constructing Reply (for Request) message ...", 1); sending_message = create_reply_message (message); // Move lease node from partial leases structure to leases structure write_to_log ("Moving node from partial lease to lease ...", 1); move_node_from_partial_to_lease (message); break; case RENEW : case REBIND : if (message -> u_msg_type.msg_type == RENEW) write_to_log ("Renew message received.", 1); else write_to_log ("Rebind message received.", 1); // Check for validity of renew/rebind message if (!check_message (message, message -> u_msg_type.msg_type)) { if (message -> u_msg_type.msg_type == RENEW) write_to_log ("Renew message received is invalid. Discarding ...", 1); else write_to_log ("Rebind message received is invalid. Discarding ...", 1); break; } if (message -> u_msg_type.msg_type == RENEW) { // Check for server duid if (!check_duid (OPTION_SERVERID, message, lease)) { write_to_log ("Failed to find client duid in leases for Renewal of lease.", 1); break; } write_to_log ("Client duid has been matched in leases for Renewal of lease.", 1); } // Check for client binding if (!check_duid (OPTION_CLIENTID, message, lease)) { sending_message = create_dummy_reply_message (message); opt_ptr = get_options_ptr (sending_message, OPTION_IA); ia_ptr = (struct IA *) opt_ptr -> opt_data; // Set IA status to indicate no record of client binding ia_ptr -> status = NoBinding; break; } // Check all values of the binding for exact match if (!check_for_match (message, lease)) { sending_message = create_dummy_reply_message (message); opt_ptr = get_options_ptr (sending_message, OPTION_IA); ia_ptr = (struct IA *) opt_ptr -> opt_data; if (message -> u_msg_type.msg_type == RENEW) { // Set IA status to indicate mismatch in binding parameters for renew message ia_ptr -> status = RenwNoMatch; } else if (message -> u_msg_type.msg_type == REBIND) { // Set IA status to indicate mismatch in binding parameters for rebind message ia_ptr -> status = RebdNoMatch; } break; } // Check renewal policy (if number of renewals has exceeded the max allowable number) if (!check_renewal_policy (message, lease)) { // Valid reply message sent sending_message = create_reply_message (message); } else { // Address unavailable sending_message = create_dummy_reply_message (message); opt_ptr = get_options_ptr (sending_message, OPTION_IA); ia_ptr = (struct IA *) opt_ptr -> opt_data; // Set IA status to indicate unavailabilty of address ia_ptr -> status = AddrUnavail; // Move lease node from leases structure to partial leases structure // Anticipating a request message move_node_from_lease_to_partial (message); } break; case DECLINE : case RELEASE : // Check for validity of message if (!check_message (message, message -> u_msg_type.msg_type)) break; // Check for duplicate decline/release message if (check_for_duplicate_packet (message)) break; // Create appropriate reply message if (message -> u_msg_type.msg_type == DECLINE) sending_message = create_reply_message_for_decline (message); else if (message -> u_msg_type.msg_type == RELEASE) sending_message = create_reply_message_for_release (message); // Delete node from leases structure del_node_from_lease (message, lease); break; default :#if DEBUG == 2 printf ("\nInvalid message type received\n");#endif sending_message = 0; break; } if (sending_message) {#if DEBUG == 2 print_linked_list_contents (sending_message);#endif message_len = store_in_buffer (sending_message, udp_message); sendto (sending_socket, udp_message, message_len, 0, (struct sockaddr *) &client_address, cl); // Free message linked list free_message_mem (sending_message); } // Free message linked list free_message_mem (message); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -