Skip to content

Instantly share code, notes, and snippets.

@phhusson
Created January 3, 2025 13:35
Show Gist options
  • Save phhusson/87c42bc100f78cbdce9e92ec649d7096 to your computer and use it in GitHub Desktop.
Save phhusson/87c42bc100f78cbdce9e92ec649d7096 to your computer and use it in GitHub Desktop.
dhcp-inform for sip server ( = get p-cscf server for ims)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <ifaddrs.h>
#include <net/if.h>
#define DHCPV6_CLIENT_PORT 546
#define DHCPV6_SERVER_PORT 547
#define DHCPV6_MULTICAST_GROUP "FF02::1:2"
#define DHCPV6_INFORMATION_REQUEST 11
#define DHCPV6_DNS_SERVERS 23
#define DHCPV6_DOMAIN_LIST 24
#define SIP_SERVER_D 21
#define SIP_SERVER_A 22
#define OPTION_REQUEST_OPTION 6
// Function to create a DHCPv6 Information Request packet
int create_dhcpv6_info_request(unsigned char *packet) {
// DHCPv6 Message Type (Information Request)
int i = 0;
packet[i++] = 1;//solicit 11; // information request
// Transaction ID (random 3 bytes)
packet[i++] = rand();
packet[i++] = rand();
packet[i++] = rand();
// Options
// Option: DNS Servers (23)
#if 0
packet[i++] = (DHCPV6_DNS_SERVERS >> 8) & 0xFF;
packet[i++] = DHCPV6_DNS_SERVERS & 0xFF;
packet[i++] = 0x00; // Length (0 for now, will be filled later)
packet[i++] = 0x00;
// Option: Domain List (24)
packet[i++] = (DHCPV6_DOMAIN_LIST >> 8) & 0xFF;
packet[i++] = DHCPV6_DOMAIN_LIST & 0xFF;
packet[i++] = 0x00; // Length (0 for now, will be filled later)
packet[i++] = 0x00;
packet[i++] = (SIP_SERVER_A >> 8) & 0xFF;
packet[i++] = SIP_SERVER_A & 0xFF;
packet[i++] = 0x00; // Length (0 for now, will be filled later)
packet[i++] = 0x00;
// Option: Domain List (24)
packet[i++] = (SIP_SERVER_D >> 8) & 0xFF;
packet[i++] = SIP_SERVER_D & 0xFF;
packet[i++] = 0x00; // Length (0 for now, will be filled later)
packet[i++] = 0x00;
#endif
packet[i++] = (OPTION_REQUEST_OPTION >> 8) & 0xFF;
packet[i++] = OPTION_REQUEST_OPTION & 0xFF;
packet[i++] = 0;
packet[i++] = 8;
packet[i++] = (DHCPV6_DNS_SERVERS >> 8) & 0xFF;
packet[i++] = DHCPV6_DNS_SERVERS & 0xFF;
packet[i++] = (DHCPV6_DOMAIN_LIST >> 8) & 0xFF;
packet[i++] = DHCPV6_DOMAIN_LIST & 0xFF;
packet[i++] = (SIP_SERVER_D >> 8) & 0xFF;
packet[i++] = SIP_SERVER_D & 0xFF;
packet[i++] = (SIP_SERVER_A >> 8) & 0xFF;
packet[i++] = SIP_SERVER_A & 0xFF;
// Option: End (255)
packet[i++] = 0xFF;
return i;
}
// Function to get the interface index by name
int get_interface_index(const char *ifname) {
struct ifaddrs *ifaddr, *ifa;
int ifindex = -1;
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
if (strcmp(ifa->ifa_name, ifname) == 0) {
ifindex = if_nametoindex(ifa->ifa_name);
break;
}
}
freeifaddrs(ifaddr);
return ifindex;
}
// Function to send the DHCPv6 Information Request packet
void send_dhcpv6_info_request(const char *ifname) {
int sockfd;
struct sockaddr_in6 server_addr;
unsigned char packet[1024];
int packet_len;
int ifindex;
// Create a raw socket
sockfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (sockfd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
// Set the interface index for sending multicast packets
ifindex = get_interface_index(ifname);
if (ifindex == -1) {
perror("get_interface_index");
close(sockfd);
exit(EXIT_FAILURE);
}
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0) {
perror("setsockopt");
close(sockfd);
exit(EXIT_FAILURE);
}
struct sockaddr_in6 serv_addr;
socklen_t addrlen = sizeof(serv_addr);
// Prepare the sockaddr_in6 structure
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin6_family = AF_INET6;
serv_addr.sin6_addr = in6addr_any; // Bind to all available IPv6 addresses
serv_addr.sin6_port = htons(546); // DHCPv6 client port
// Bind the socket to the DHCPv6 client port
if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("Bind failed");
close(sockfd);
exit(EXIT_FAILURE);
}
// Set up the server address
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin6_family = AF_INET6;
server_addr.sin6_port = htons(DHCPV6_SERVER_PORT);
inet_pton(AF_INET6, DHCPV6_MULTICAST_GROUP, &server_addr.sin6_addr);
// Create the DHCPv6 Information Request packet
packet_len = create_dhcpv6_info_request(packet);
// Send the packet
if (sendto(sockfd, packet, packet_len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("sendto");
close(sockfd);
exit(EXIT_FAILURE);
}
printf("DHCPv6 Information Request sent successfully on interface %s.\n", ifname);
// Close the socket
close(sockfd);
}
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <interface>\n", argv[0]);
exit(EXIT_FAILURE);
}
const char *ifname = argv[1];
send_dhcpv6_info_request(ifname);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment