Skip to content

Instantly share code, notes, and snippets.

@mittorn
Last active July 26, 2023 04:06
Show Gist options
  • Save mittorn/d7dc8f2a830f086cf74c73a9f65a2206 to your computer and use it in GitHub Desktop.
Save mittorn/d7dc8f2a830f086cf74c73a9f65a2206 to your computer and use it in GitHub Desktop.
Static linking helpers. Static-linked glibc tries to load current glibc version dynamically, this is to workaround this mess
// this prevents using glibc's dinamic linker features (which may cause failure)
// remove -ldl when linking it, this should remove static linking warning
// if you really need dlopen implementation that works in static binary,
// try https://github.com/mittorn/custom-linker or android bionic linker
void *dlopen( const char *n, int f )
{
return 0;
}
void *dlsym( void *l, const char *n )
{
return 0;
}
const char *dlerror()
{
return "dlerror";
}
int dlclose( void *lib )
{
return 0;
}
int dladdr(void *addr, void *info)
{
return 0;
}
/*
simple dns resolver
glibc have dns resolver in separate libnss_dns, which does not link staticly
btw, other libc implementations usually have hard-coded resolv.conf path, so it will fail if there is no resolv.conf on the target system
only getaddrinfo implemented, i'm too lazy to add gethostbyname now
linking it should exclude glibc's gettaddrinfo.o and gethstbynm.o and remove static linking warning
based on some code found in the internet, orginal author is Silver Moon (m00n.silv3r@gmail.com) 29/4/2009
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#define T_A 1 //Ipv4 address
//DNS header structure
struct DNS_HEADER
{
unsigned short id; // identification number
unsigned char rd :1; // recursion desired
unsigned char tc :1; // truncated message
unsigned char aa :1; // authoritive answer
unsigned char opcode :4; // purpose of message
unsigned char qr :1; // query/response flag
unsigned char rcode :4; // response code
unsigned char cd :1; // checking disabled
unsigned char ad :1; // authenticated data
unsigned char z :1; // its z! reserved
unsigned char ra :1; // recursion available
unsigned short q_count; // number of question entries
unsigned short ans_count; // number of answer entries
unsigned short auth_count; // number of authority entries
unsigned short add_count; // number of resource entries
};
//Constant sized fields of query structure
struct QUESTION
{
unsigned short qtype;
unsigned short qclass;
};
//Constant sized fields of the resource record structure
#pragma pack(push, 1)
struct R_DATA
{
unsigned short type;
unsigned short _class;
unsigned int ttl;
unsigned short data_len;
};
#pragma pack(pop)
//Structure of a Query
typedef struct
{
unsigned char *name;
struct QUESTION *ques;
} QUERY;
/*
* This will convert www.google.com to 3www6google3com
* got it :)
* */
static void ChangetoDnsNameFormat(unsigned char* dns,const char* host)
{
int lock = 0 , i, len = strlen( host)+1;
//strcat((char*)host,".");
for(i = 0 ; i < len ; i++)
{
if(host[i]=='.'|| host[i] == 0)
{
*dns++ = i-lock;
for(;lock<i;lock++)
{
*dns++=host[lock];
}
lock++; //or lock=i+1;
}
}
*dns++='\0';
}
/*
*
* */
static int skip_name(unsigned char* reader,unsigned char* buffer)
{
unsigned int p=0,jumped=0,offset;
int count = 1;
while(*reader)
{
if(*reader>=192)
{
offset = (*reader)*256 + *(reader+1) - 49152; //49152 = 11000000 00000000 ;)
reader = buffer + offset - 1;
jumped = 1; //we have jumped to another location so counting wont go up!
}
else p++;
reader++;
if(jumped==0) count++;
}
if(jumped==1) count++;
return count;
}
/*
* Perform a DNS query by sending a packet
* */
static unsigned int dns_lookup(const char *host)
{
unsigned char buf[65536],*qname,*reader;
int i, s;
socklen_t len;
//struct sockaddr_in a;
//struct RES_RECORD answers[20],auth[20],addit[20]; //the replies from the DNS server
struct sockaddr_in dest;
struct DNS_HEADER *dns = NULL;
struct QUESTION *qinfo = NULL;
s = socket(AF_INET , SOCK_DGRAM , IPPROTO_UDP); //UDP packet for DNS queries
dest.sin_family = AF_INET;
dest.sin_port = htons(53);
dest.sin_addr.s_addr = inet_addr("8.8.8.8"); //dns servers
//Set the DNS structure to standard queries
dns = (struct DNS_HEADER *)&buf;
dns->id = (unsigned short) htons(getpid());
dns->qr = 0; //This is a query
dns->opcode = 0; //This is a standard query
dns->aa = 0; //Not Authoritative
dns->tc = 0; //This message is not truncated
dns->rd = 1; //Recursion Desired
dns->ra = 0; //Recursion not available! hey we dont have it (lol)
dns->z = 0;
dns->ad = 0;
dns->cd = 0;
dns->rcode = 0;
dns->q_count = htons(1); //we have only 1 question
dns->ans_count = 0;
dns->auth_count = 0;
dns->add_count = 0;
//point to the query portion
qname =(unsigned char*)&buf[sizeof(struct DNS_HEADER)];
ChangetoDnsNameFormat(qname , host);
printf("%s %d %d %d %s\n", qname, qname[0], qname[3], qname[7], host);
qinfo =(struct QUESTION*)&buf[sizeof(struct DNS_HEADER) + (strlen(host) + 2)]; //fill it
qinfo->qtype = htons( T_A ); //type of the query , A , MX , CNAME , NS etc
qinfo->qclass = htons(1); //its internet (lol)
if( sendto(s,(char*)buf,sizeof(struct DNS_HEADER) + (strlen((const char*)host)+2) + sizeof(struct QUESTION),0,(struct sockaddr*)&dest,sizeof(dest)) < 0)
perror("sendto failed");
//Receive the answer
len = sizeof( dest );
// printf("\nReceiving answer...");
if(recvfrom (s,(char*)buf , 65536 , 0 , (struct sockaddr*)&dest , &len ) < 0)
perror("recvfrom failed");
dns = (struct DNS_HEADER*) buf;
//move ahead of the dns header and the query field
reader = &buf[sizeof(struct DNS_HEADER) + (strlen((const char*)host)+2) + sizeof(struct QUESTION)];
for(i=0;i<ntohs(dns->ans_count);i++)
{
struct R_DATA *res;
//puts(reader);
reader += skip_name(reader, buf);
res = (struct R_DATA*)(reader);
reader += sizeof(struct R_DATA);
if(ntohs(res->type) == 1) //if its an ipv4 address
{
close(s);
// printf("%d\n", reader - buf);
return *(unsigned int*)reader;
}
else reader += skip_name( reader, buf );
}
//read authorities
for(i=0;i<ntohs(dns->auth_count);i++)
{
// puts(reader);
reader += skip_name( reader, buf );
reader+=sizeof(struct R_DATA);
// puts( reader);
reader += skip_name( reader, buf );
}
//read additional
for(i=0;i<ntohs(dns->add_count);i++)
{
struct R_DATA *res;
reader += skip_name( reader, buf );
//addit[i].resource
res=(struct R_DATA*)(reader);
reader+=sizeof(struct R_DATA);
if(ntohs(res->type)==1)
{
close(s);
return *(unsigned int*)reader;
}
else reader += skip_name( reader, buf );
}
close(s);
return 0;
}
char cache_names[256][32];
unsigned int cache_hosts[32];
unsigned char cache_counter;
static unsigned int dns_cache(const char *host)
{
unsigned int i;
for( i = 0; i < 32; i++ ) if(!strcmp( cache_names[i], host ) ) return cache_hosts[i];
i = dns_lookup(host);
if( i )
cache_hosts[cache_counter = ((cache_counter + 1) & 31)] = i,strncpy( cache_names[cache_counter], host, 255 );
return i;
}
static unsigned int lookup4( const char *node )
{
unsigned int address;
if( node[0] >= '0' && node[0] <= '9' )
address = inet_addr(node);
else
address = dns_cache(node);
struct sockaddr_in a;
a.sin_addr.s_addr=address;
printf("%s\n",inet_ntoa(a.sin_addr));
return address;
}
#include <pthread.h>
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
int getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints,
struct addrinfo **res)
{
*res = calloc(sizeof(struct addrinfo), 1);
(*res)->ai_family = AF_INET;
(*res)->ai_socktype = SOCK_STREAM;
(*res)->ai_protocol = IPPROTO_TCP;
(*res)->ai_addrlen = sizeof(struct sockaddr_in);
(*res)->ai_addr = malloc((*res)->ai_addrlen);
pthread_mutex_lock( &lock );
*(int *)&((struct sockaddr_in *)(*res)->ai_addr)->sin_addr = lookup4( node );
pthread_mutex_unlock( &lock );
((struct sockaddr_in *)(*res)->ai_addr)->sin_port = htons(443);
((struct sockaddr_in *)(*res)->ai_addr)->sin_family = AF_INET;
return 0;
}
void freeaddrinfo(struct addrinfo *res)
{
free(res->ai_addr);
free(res);
}
struct hostent *gethostbyname(const char *name) { return 0; }
#ifdef RES_TEST
int main( int argc, char** argv )
{
return lookup4(argv[1]) != 0;
}
#endif
// this prevents glib from using glibc's dinamic linker features (which may cause failure)
void *g_get_prgname(){return NULL;}
void g_set_prgname(void *n){}
void *g_get_tmp_dir(){return NULL;} // The return value is never NULL or the empty string.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment