Last active
April 19, 2023 21:16
-
-
Save pgassendi/d3e4fa66d513df3c88304316a788af27 to your computer and use it in GitHub Desktop.
get url info
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 <stdio.h> | |
#include <stdlib.h> | |
#include <netdb.h> | |
#include <netinet/in.h> | |
#include <sys/socket.h> | |
#define case_return(ENUM_VALUE) case ENUM_VALUE: return #ENUM_VALUE; | |
const char* get_family(int f) { | |
switch(f) { | |
case_return(AF_INET); | |
case_return(AF_INET6); | |
case_return(AF_UNSPEC); | |
default: return "Neither ipv4 not ipv6 address family"; | |
} | |
} | |
const char* get_socktype(int s) { | |
switch(s) { | |
case_return(SOCK_DGRAM); | |
case_return(SOCK_STREAM); | |
case_return(SOCK_RAW); | |
default: return "Neither raw nor dgram nor stream socket"; | |
} | |
} | |
const char* get_proto(int p) { | |
switch(p) { | |
case_return(IPPROTO_IP); | |
case_return(IPPROTO_ICMP); | |
case_return(IPPROTO_TCP); | |
case_return(IPPROTO_UDP); | |
default: return "other proto"; | |
} | |
} | |
static inline struct sockaddr_in* sa_ptr_to_in_ptr(struct sockaddr* sa) { return (struct sockaddr_in*)sa; } | |
static inline struct sockaddr_in6* sa_ptr_to_in6_ptr(struct sockaddr* sa) { return (struct sockaddr_in6*)sa; } | |
#define as_in4(SA) _Generic((SA), struct sockaddr*: sa_ptr_to_in_ptr)(SA) | |
#define as_in6(SA) _Generic((SA), struct sockaddr*: sa_ptr_to_in6_ptr)(SA) | |
#define sin_inet_ntop(SA, BUF, BUFSZ) inet_ntop(AF_INET, &(as_in4(SA)->sin_addr), BUF, BUFSZ) | |
#define sin6_inet_ntop(SA, BUF, BUFSZ) inet_ntop(AF_INET6, &(as_in6(SA)->sin6_addr), BUF, BUFSZ) | |
void print_sockaddr_row(struct sockaddr* sa, char* const sep) { | |
char buf[INET6_ADDRSTRLEN]; | |
char const* addr = 0x0; | |
in_port_t port; | |
switch(sa->sa_family) { | |
case AF_INET: { | |
addr = sin_inet_ntop(sa, buf, sizeof(buf)); | |
port = as_in4(sa)->sin_port; | |
break; | |
} | |
case AF_INET6: { | |
addr = sin6_inet_ntop(sa, buf, sizeof(buf)); | |
port = as_in6(sa)->sin6_port; | |
break; | |
} | |
case AF_UNSPEC: { printf("AF_UNSPEC"); } | |
default: { fprintf(stderr, "unsupported sockaddr family"); return; } | |
} | |
if (addr) { | |
printf("%-40s%s%d", addr, sep, port); | |
} else { | |
fprintf(stderr, "inet_ntop error"); | |
} | |
} | |
void print_addrinfo_row(const char* url, struct addrinfo* ai, char* const sep) { | |
printf("%s%s" "0x%x%s" "%-8s%s" "%s%s" "%s%s" "%d%s" "%s%s", | |
url, sep, | |
ai->ai_flags, sep, | |
get_family(ai->ai_family), sep, | |
get_socktype(ai->ai_socktype), sep, | |
get_proto(ai->ai_protocol), sep, | |
ai->ai_addrlen, sep, | |
ai->ai_canonname, sep | |
); | |
print_sockaddr_row(ai->ai_addr, sep); | |
puts(""); | |
} | |
void print_addrinfo_header(char* const sep) { | |
printf("url\t%s" "flags%s" "familiy %s" "socktype%s" "protocol%s" | |
"addrlen%s" "cname%s" "address %s" | |
"port\n", | |
sep, sep, sep, sep ,sep ,sep ,sep, sep | |
); | |
} | |
int print_info(const char* url, char* const sep) { | |
struct addrinfo* result; | |
int error = getaddrinfo(url, NULL, NULL, &result); | |
if (error != 0) { | |
fprintf(stderr, "%s: error in getaddrinfo: %s\n", url, gai_strerror(error)); | |
return EXIT_FAILURE; | |
} | |
for (struct addrinfo* res = result; res != NULL; res = res->ai_next) { | |
print_addrinfo_row(url, res, sep); | |
} | |
freeaddrinfo(result); | |
return EXIT_SUCCESS; | |
} | |
int main(int argc, char* argv[]) { | |
char* const sep = "\t"; | |
print_addrinfo_header(sep); | |
for (int i = 1; i < argc; ++i) { | |
print_info(argv[i], sep); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment