Created
March 5, 2024 17:01
-
-
Save karstenBriksoft/459d678b7716a8f8e9bb1cb7ce211375 to your computer and use it in GitHub Desktop.
example of how to do a UDP broadcast request for finding local Samba sharing servers.
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
#include <arpa/inet.h> | |
#include <netinet/in.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <sys/_types/_socklen_t.h> | |
#include <sys/select.h> | |
#include <sys/socket.h> | |
#include <sys/types.h> | |
// based on the example from https://github.com/pyang30/linux-udp-broadcast-example/tree/master | |
// adapted to macOS 14.3 | |
// WINS works on Port 137 | |
#define PORT 137 | |
// this is an example packet that sends a request for the WORKGROUP servers | |
char packet[] = {0x06, 0x51, 0x01, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x46, 0x48, 0x45, 0x50, | |
0x46, 0x43, 0x45, 0x4C, 0x45, 0x48, 0x46, 0x43, 0x45, 0x50, 0x46, 0x46, 0x46, 0x41, 0x43, 0x41, 0x43, | |
0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x41, 0x41, 0x00, 0x00, 0x20, 0x00, 0x01}; | |
size_t packetSize = sizeof(packet); | |
int main() | |
{ | |
int sock; | |
int yes = 1; | |
struct sockaddr_in broadcast_addr; | |
struct sockaddr_in server_addr; | |
socklen_t addr_len; | |
int count; | |
int ret; | |
fd_set readfd; | |
uint8_t buffer[1024]; | |
int i; | |
sock = socket(AF_INET, SOCK_DGRAM, 0); | |
if (sock < 0) | |
{ | |
perror("sock error"); | |
return -1; | |
} | |
ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&yes, sizeof(yes)); | |
if (ret == -1) | |
{ | |
perror("setsockopt error"); | |
return -1; | |
} | |
addr_len = sizeof(struct sockaddr_in); | |
memset((void*)&broadcast_addr, 0, addr_len); | |
broadcast_addr.sin_family = AF_INET; | |
broadcast_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); | |
broadcast_addr.sin_port = htons(PORT); | |
ret = sendto(sock, packet, packetSize, 0, (struct sockaddr*)&broadcast_addr, addr_len); | |
if (ret == -1) | |
{ | |
perror("failed to send"); | |
return -1; | |
} | |
FD_ZERO(&readfd); | |
FD_SET(sock, &readfd); | |
struct timeval timeout = {0}; | |
timeout.tv_usec = 50000; | |
for (i = 0; i < 30; i++) | |
{ | |
ret = select(sock + 1, &readfd, NULL, NULL, &timeout); | |
if (ret > 0) | |
{ | |
if (FD_ISSET(sock, &readfd)) | |
{ | |
count = recvfrom(sock, buffer, 1024, 0, (struct sockaddr*)&server_addr, &addr_len); | |
if (addr_len > 0) | |
{ | |
// it may not be a wrong assumption to just take this address, it's from a server at least | |
uint8_t* addr = (uint8_t*)&(server_addr.sin_addr.s_addr); | |
printf("answer from: %i.%i.%i.%i\n", addr[0], addr[1], addr[2], addr[3]); | |
} | |
printf("\treceived %i bytes\n\t\tIP: ", count); | |
// the answer of a WINS package contains the IP-Address in its last 4 bytes | |
// this may be identical to the information found in server_addr (printed already) | |
for (int i = count - 4; i < count; i++) | |
{ | |
unsigned b = buffer[i]; | |
printf("%02i", b); | |
if (i == count - 1) | |
{ | |
printf("\n"); | |
} | |
else | |
{ | |
printf("."); | |
} | |
} | |
} | |
} | |
else | |
{ | |
// no more sockets to read from? | |
break; | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If you add the following after the call to
setsockopt
, then you can also broadcast on other than the default interface, and then the IP addr extracted may indeed be different from the one printed first, i.e. the first IP would be the one from which the host responds and the other one is the one where its primary interface is on.Also, that
1024
in therecvfrom
call should be changed tosizeof(buffer)
.