Created
July 11, 2018 16:05
-
-
Save Aketzu/2d800f292e526a85a9448519f0c4cc2b to your computer and use it in GitHub Desktop.
Local webserver to provice MAC address
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Compile with -lmicrohttpd | |
#include <arpa/inet.h> | |
#include <errno.h> | |
#include <limits.h> | |
#include <linux/rtnetlink.h> | |
#include <linux/types.h> | |
#include <microhttpd.h> | |
#include <net/if.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/ioctl.h> | |
#include <sys/socket.h> | |
#include <sys/time.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
struct route_info { | |
struct in_addr dstAddr; | |
struct in_addr srcAddr; | |
struct in_addr gateWay; | |
char ifName[IF_NAMESIZE]; | |
}; | |
/* Code by gibbon1 | |
* http://www.linuxquestions.org/questions/linux-networking-3/howto-find-gateway-address-through-code-397078/ | |
*/ | |
#define BUFSIZE 8192 | |
int readNlSock(int sockFd, char *bufPtr, unsigned int seqNum, unsigned int pId) { | |
struct nlmsghdr *nlHdr; | |
int msgLen = 0; | |
do { | |
int readLen = 0; | |
/* Receive response from the kernel */ | |
if ((readLen = recv(sockFd, bufPtr, BUFSIZE - msgLen, 0)) < 0) { | |
perror("SOCK READ: "); | |
return -1; | |
} | |
nlHdr = (struct nlmsghdr *)bufPtr; | |
/* Check if the header is valid */ | |
if ((NLMSG_OK(nlHdr, readLen) == 0) || (nlHdr->nlmsg_type == NLMSG_ERROR)) { | |
perror("Error in recieved packet"); | |
return -1; | |
} | |
/* Check if the its the last message */ | |
if (nlHdr->nlmsg_type == NLMSG_DONE) { | |
break; | |
} else { | |
/* Else move the pointer to buffer appropriately */ | |
bufPtr += readLen; | |
msgLen += readLen; | |
} | |
/* Check if its a multi part message */ | |
if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0) { | |
/* return if its not */ | |
break; | |
} | |
} while ((nlHdr->nlmsg_seq != seqNum) || (nlHdr->nlmsg_pid != pId)); | |
return msgLen; | |
} | |
/* parse the route info returned */ | |
int parseRoutes(struct nlmsghdr *nlHdr, struct route_info *rtInfo) { | |
struct rtmsg *rtMsg; | |
struct rtattr *rtAttr; | |
int rtLen; | |
rtMsg = (struct rtmsg *)NLMSG_DATA(nlHdr); | |
/* If the route is not for AF_INET or does not belong to main routing table then return. */ | |
if ((rtMsg->rtm_family != AF_INET) || (rtMsg->rtm_table != RT_TABLE_MAIN)) | |
return 1; | |
/* get the rtattr field */ | |
rtAttr = (struct rtattr *)RTM_RTA(rtMsg); | |
rtLen = RTM_PAYLOAD(nlHdr); | |
for ( ; RTA_OK(rtAttr, rtLen) ; rtAttr = RTA_NEXT(rtAttr, rtLen)) { | |
switch (rtAttr->rta_type) { | |
case RTA_OIF: | |
if_indextoname(*(int *)RTA_DATA(rtAttr), rtInfo->ifName); | |
break; | |
case RTA_GATEWAY: | |
memcpy(&rtInfo->gateWay, RTA_DATA(rtAttr), sizeof(rtInfo->gateWay)); | |
break; | |
case RTA_PREFSRC: | |
memcpy(&rtInfo->srcAddr, RTA_DATA(rtAttr), sizeof(rtInfo->srcAddr)); | |
break; | |
case RTA_DST: | |
memcpy(&rtInfo->dstAddr, RTA_DATA(rtAttr), sizeof(rtInfo->dstAddr)); | |
break; | |
} | |
} | |
return 0; | |
} | |
// meat | |
int get_gatewayif(char *gatewayif, socklen_t size) { | |
int found_gatewayip = 0; | |
struct nlmsghdr *nlMsg; | |
struct rtmsg *rtMsg; | |
struct route_info *rtInfo; | |
char msgBuf[BUFSIZE]; // pretty large buffer | |
int sock, len, msgSeq = 0; | |
/* Create Socket */ | |
if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) { | |
perror("Socket Creation: "); | |
return(-1); | |
} | |
/* Initialize the buffer */ | |
memset(msgBuf, 0, BUFSIZE); | |
/* point the header and the msg structure pointers into the buffer */ | |
nlMsg = (struct nlmsghdr *)msgBuf; | |
rtMsg = (struct rtmsg *)NLMSG_DATA(nlMsg); | |
rtMsg->rtm_table = RT_TABLE_MAIN; | |
/* Fill in the nlmsg header*/ | |
nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); // Length of message. | |
nlMsg->nlmsg_type = RTM_GETROUTE; // Get the routes from kernel routing table . | |
nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; // The message is a request for dump. | |
nlMsg->nlmsg_seq = msgSeq++; // Sequence of the message packet. | |
nlMsg->nlmsg_pid = getpid(); // PID of process sending the request. | |
/* Send the request */ | |
if (send(sock, nlMsg, nlMsg->nlmsg_len, 0) < 0) { | |
fprintf(stderr, "Write To Socket Failed...\n"); | |
return -1; | |
} | |
/* Read the response */ | |
if ((len = readNlSock(sock, msgBuf, msgSeq, getpid())) < 0) { | |
fprintf(stderr, "Read From Socket Failed...\n"); | |
return -1; | |
} | |
/* Parse and print the response */ | |
rtInfo = (struct route_info *)malloc(sizeof(struct route_info)); | |
for ( ; NLMSG_OK(nlMsg, len); nlMsg = NLMSG_NEXT(nlMsg, len)) { | |
memset(rtInfo, 0, sizeof(struct route_info)); | |
if (parseRoutes(nlMsg, rtInfo)) | |
continue; | |
// Check if default gateway | |
if (strstr((char *)inet_ntoa(rtInfo->dstAddr), "0.0.0.0")) { | |
// copy it over | |
//inet_ntop(AF_INET, &rtInfo->gateWay, gatewayip, size); | |
strncpy(gatewayif, rtInfo->ifName, size); | |
found_gatewayip = 1; | |
break; | |
} | |
} | |
free(rtInfo); | |
close(sock); | |
return found_gatewayip; | |
} | |
int getmac(uint8_t mac[]) { | |
int sock; | |
struct ifreq ifr = {}; | |
ifr.ifr_addr.sa_family = AF_INET; | |
sock = socket(AF_INET, SOCK_DGRAM, 0); | |
if (!sock) | |
return 1; | |
if (!get_gatewayif(ifr.ifr_name, sizeof(ifr.ifr_name))) { | |
printf("Cannot get gateway interface, defaulting to eth0 mac\n"); | |
strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name)); | |
} | |
ioctl(sock, SIOCGIFHWADDR, &ifr); | |
close(sock); | |
int i; | |
for (i=0; i<6; i++) { | |
mac[i] = ifr.ifr_hwaddr.sa_data[i]; | |
} | |
return 0; | |
} | |
struct MHD_Daemon *httpd = 0; | |
void httpd_request_completed(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe) { | |
(void)cls; | |
(void)connection; | |
(void)toe; | |
*con_cls = NULL; | |
} | |
int httpd_process_query(void * cls, | |
struct MHD_Connection * connection, | |
const char * url, | |
const char * method, | |
const char * version, | |
const char * upload_data, | |
size_t * upload_data_size, | |
void ** ptr) { | |
(void)version; | |
(void)cls; | |
struct MHD_Response * response; | |
int ret; | |
char * resp=0; | |
int returncode = MHD_HTTP_OK; | |
size_t resplength = 0; | |
if (strcmp(method, "GET")) { | |
return MHD_NO; | |
} | |
if (strcmp(url, "/")==0) { | |
resp = strdup("MAC server"); | |
} | |
if (strcmp(url, "/mac")==0) { | |
uint8_t mac[6] = {}; | |
char buf[20]; | |
if (!getmac(mac)) { | |
snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", | |
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); | |
resp = strdup(buf); | |
} else { | |
resp = strdup("Error"); | |
} | |
} | |
if (resp==0) { | |
resp = strdup(""); | |
returncode = MHD_HTTP_NOT_FOUND; | |
} | |
if (resplength == 0 && resp) { | |
resplength = strlen(resp); | |
} | |
response = MHD_create_response_from_buffer(resplength, (void*)resp, MHD_RESPMEM_MUST_FREE); | |
if (returncode == MHD_HTTP_OK) { | |
MHD_add_response_header(response, "Content-Type", "text/plain"); | |
} | |
MHD_add_response_header(response, "Access-Control-Allow-Origin", "*"); | |
ret = MHD_queue_response(connection, | |
returncode, | |
response); | |
MHD_destroy_response(response); | |
return ret; | |
} | |
int main(int argc, char **argv) { | |
httpd = MHD_start_daemon( | |
MHD_USE_SELECT_INTERNALLY+MHD_USE_DEBUG+MHD_USE_DUAL_STACK, | |
8080, | |
NULL, | |
NULL, | |
&httpd_process_query, | |
NULL, | |
MHD_OPTION_NOTIFY_COMPLETED, httpd_request_completed, NULL, | |
MHD_OPTION_CONNECTION_TIMEOUT, 30, | |
MHD_OPTION_END); | |
while (1) { | |
sleep(1); | |
} | |
MHD_stop_daemon(httpd); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment