libiptc : adding nat rule with mark based match? - c

Am using libiptc -library to manipulate the iptables programatically to add nat rule similar to below.
Rule : iptables -t nat -A POSTROUTING -m mark --mark 0x2/0x3 -j SNAT --to 1.1.1.1
The code looks like below.
I understand that iptable nat rules = ipt_entry (IP Header) + ipt_entry_match (match) + ipt_entry_target (target).
// function to create Mark based match
struct ipt_entry_match* get_mark_target() {
struct ipt_entry_match *match;
struct xt_mark_info *m;
size_t size;
size = IPT_ALIGN(sizeof(struct ipt_entry_match))
+ IPT_ALIGN(sizeof(struct xt_mark_info));
match = calloc(1, size);
match->u.match_size = size;
strncpy(match->u.user.name, "mark", sizeof(match->u.user.name));
m = (struct xt_mark_info*)match->data;
m->mark = m->mask = 0xff;
return match;
}
//function : to create final ipt_enrty
static struct ipt_entry*
make_entry(const char * iaddr, const char * rhost, const char *chain_target)
{
int r = 0;
struct ipt_entry * e;
struct ipt_entry_match *match = get_mark_target();
struct xt_mark_info *m = NULL;
struct ipt_entry_target *target = NULL;
e = calloc(1, sizeof(struct ipt_entry));
//m = calloc(1, sizeof(*m));
//m->mark = 0xff;
e->ip.proto = IPPROTO_IP;
e->nfcache = NFC_IP_DST_PT;
if (!strcmp(chain_target, "SNAT")) {
e->ip.src.s_addr = inet_addr(rhost);
e->ip.smsk.s_addr = INADDR_NONE;
//e->ip.smsk.s_addr = INADDR_NONE;
printf("\n SNAT");
target = get_snat_target(iaddr, 0);
} else {
printf("\n DNAT");
e->ip.dst.s_addr = inet_addr(rhost);
e->ip.dmsk.s_addr = INADDR_NONE;
target = get_dnat_target(iaddr, 0);
}
e->nfcache |= NFC_UNKNOWN;
e = realloc(e, sizeof(struct ipt_entry)
+ match->u.match_size + target->u.target_size);
memcpy(e->elems, match, match->u.match_size);
memcpy(e->elems + match->u.match_size, target, target->u.target_size);
e->target_offset = sizeof(struct ipt_entry)
+ match->u.match_size;
e->next_offset = sizeof(struct ipt_entry)
+ match->u.match_size + target->u.target_size;
#if 0
e = realloc(e, sizeof(struct ipt_entry) + sizeof(*m));
//+ target->u.target_size);
//memcpy(e->elems , target, target->u.target_size);
memcpy(e->elems , m, sizeof(*m));
e->target_offset = sizeof(struct ipt_entry);
e->next_offset = sizeof(struct ipt_entry) + sizeof(*m);
#endif
free(target);
//free(m);
return e;
}
static int
insert_nat_rule (char *src, char *dest, int op, const char *target)
{
struct ipt_entry *entry;
struct xtc_handle *h;
int ret = 1;
const char *chain, *table = "nat";
char *match_mask;
h = iptc_init (table);
if (!h) {
fprintf (stderr, "Could not init IPTC library: %s\n", iptc_strerror (errno));
goto out;
}
if (!strcmp(target, "SNAT")) {
chain = "POSTROUTING";
} else if (!strcmp(target, "DNAT")) {
chain = "PREROUTING";
} else {
//invlid target
return 0;
}
entry = make_entry(src, dest, target);
if (op) {
if (!iptc_append_entry (chain, (struct ipt_entry *) entry, h)) {
fprintf (stderr, "Could not insert a rule in iptables (table %s): "
"%s\n", table, iptc_strerror (errno));
goto out;
}
} else {
match_mask = (unsigned char *)malloc(entry->next_offset);
memset(match_mask, 0xFF, entry->next_offset);
if (!iptc_delete_entry (chain, (struct ipt_entry *) entry,
match_mask, h)) {
fprintf (stderr, "Could not delete a rule in iptables (table %s): "
"%s\n", table, iptc_strerror (errno));
goto out;
}
}
if (!iptc_commit (h)) {
fprintf (stderr, "Could not commit changes in iptables (table %s): %s\n"
, table, iptc_strerror (errno));
goto out;
}
ret = 0;
out:
if (entry) free(entry);
if (h) iptc_free (h);
return ret;
}
On executing the above program, we get an error saying "Protocol wrong type for socket". Without the mark based match this works fine, am able to add 1 to 1 SNAT rules without any problems.
Tried multiple structures for mark based match, but that does not seem to work.
Is there something obvious that I am missing ?
Will Appreciate the inputs. Thanks.

Learnt it the hard way, that iptables uses different structures for match & target. The API uses "revision" field to differentiate which structures to use for this particular match/ target.
So adding a line below, made my life easier.
match->u.user.revision = 1;

Related

Key value wont print, despite being used to sort data, looking for the reason why?

I am currently a student learning data structures, particularly the hashmap. I have been attempting to print my results at the end of my program through a printf command in the main function. Despite the fact that I use these keys in the previous while loop, I can not get the keys to print in my final part
I have tried checking in the insertMap function (seen below) by using a print to indicate whether the key has actually been stored, and It has been, so that doesn't happen to be the error.
int main (int argc, const char * argv[]) {
/*Write this function*/
const char * filename = argv[1];
struct hashMap ht;
char * entWord;
int * oldAt;
int repAt;
int i = 0;
FILE * fp = fopen(filename, "r");
initMap(&ht, 100);
while(!feof(fp)){
entWord = getWord(fp);
/* printf("%s \n", entWord); */
if(!containsKey(&ht,entWord))
insertMap(&ht, entWord, 1);
else{
oldAt = atMap(&ht, entWord);
repAt = *oldAt;
removeKey(&ht, entWord);
insertMap(&ht, entWord, repAt+1);
}
free(entWord);
}
for(i = 0; i < ht.tableSize; i++){
if(ht.table[i] != NULL){
printf("%s: %d \n",ht.table[i]->key,ht.table[i]->value);
}
}
fclose(fp);
return 0;
}
void insertMap (struct hashMap * ht, KeyType k, ValueType v)
{ /*write this*/
int idx = stringHash1(k) % ht->tableSize;
struct hashLink * hlnk;
struct hashLink * plink;
assert(ht);
if(ht->table[idx] == NULL){
hlnk = (struct hashLink *) malloc(sizeof(struct hashLink));
hlnk->value = v;
hlnk->key = k;
hlnk->next = NULL;
ht->table[idx] = hlnk;
ht->count++;
}
else{
plink = ht->table[idx];
hlnk = (struct hashLink *) malloc(sizeof(struct hashLink));
hlnk->value = v;
hlnk->key = k;
hlnk->next = plink->next;
plink->next = hlnk;
ht->count++;
}
}

My struct is overlapping some data from the previous one (Edit)

Hi guys I'm having a problem with pointers and memory this is my data structure:
struct user_node {
char *name;
struct user_node *next;
struct msg_node *msgnext;
};
struct msg_node {
char *sender;
char *receiver;
char *title;
char *content;
struct msg_node *msgnext;
};
Each user have a name and a linked list which store messages.
I already have the user creation / deletion implemented but I'm having trouble implementing new msg, I'm using this functions:
struct msg_node* sendForm(char** res) { // Format msg before sending
struct msg_node *temp = (struct msg_node*) malloc(sizeof(struct msg_node));
char *aux = malloc(sizeof(char) * 400);
int i;
temp->sender = res[1];
temp->receiver = res[2];
temp->title = res[3];
for (i = 4; i < (n_spaces + 1); i++) {
if (res[i] != NULL) {
strcat(aux, res[i]);
strcat(aux, " ");
}
}
temp->content = aux;
return temp;
}
int sendMsg(struct msg_node* msg)
{
struct user_node* user = user_database;
if (user == NULL) {
printf("There aren't users on the system.\n");
return -1;
}
while (user != NULL) {
if (strncmp(user->name, msg->receiver, strlen(msg->receiver)) == 0) {
msg->msgnext = user->msgnext;
user->msgnext = msg;
readmsglist();
return 0;
}
user = user->next;
}
printf("User '%s' not found on the system.\n", msg->receiver);
return -1;
}
This is actually working if I only input one msg but when I try to implement the second one this is what's happening:
Execution:
Welcome to the Program> Enter command (h for help):register user
User created
There are 1 users right now
> Enter command (h for help):send RandomUser1 user content1 a b c
Receiver -> user
Sender -> RandomUser1
Subject -> content1
Content:
a b c
> Enter command (h for help):send RandomUser2 user content2 d e f
Receiver -> user
Sender -> RandomUser2
Subject -> content2
Content:
d e f
Receiver -> user
Sender -> RandomUser2
Subject -> content2
Content:
a b c
and so more...
The weirdest part here is that the content is never overlaped but the other parts actually are.
Btw Sorry for my previous post that had to much code.
Edit: (Data output function)
void readmsglist() { // Show the msg of the first user Test Purposes
struct msg_node** ptr = &user_database->msgnext;
while (*ptr) {
printf("Receiver -> %s\n", (*ptr)->receiver);
printf("Sender -> %s\n", (*ptr)->sender);
printf("Subject -> %s\n", (*ptr)->title);
printf("Content:\n %s\n", (*ptr)->content);
ptr = &(*ptr)->msgnext;
}
}
Edit2 (More info):
First, the function is called here:
case 24: //Send messages
if (countSpaces(input) > 2) {
sendMsg(sendForm(cut(input)));
} else {
E_Type();
}
break;
This is the cut function:
char** cut(char str[]) {
char ** res = NULL;
char * p = strtok(str, " ");
n_spaces = 0; // Global variable (int)
/* split string and append tokens to 'res' */
while (p) {
res = realloc(res, sizeof(char*) * ++n_spaces);
if (res == NULL)
exit(-1); /* memory allocation failed */
res[n_spaces - 1] = p;
p = strtok(NULL, " ");
}
/* realloc one extra element for the last NULL */
res = realloc(res, sizeof(char*) * (n_spaces + 1));
res[n_spaces] = 0;
return res;
}
The input is like -> send :
Edw4d and I had a long discussion and debugging session.
The message data is being overwritten by user input because the location of the data in input buffer in each message is being stored in each message node, rather than actually copying the string into a new buffer. This solves the problem:
char** cut(char str[])
{
char *p = strtok(str, " "); // We don't need the first token.
p = strtok(NULL, " ");
char **res = calloc(sizeof(char*), 4); /* allocate a buffer full of NULL's*/
if (res == NULL) exit(-1); /* memory allocation failed */
/* split string and append tokens to 'res' */
for (int idx = 0; idx < 3; idx++)
{
res[idx] = malloc(strlen(p) + 1);
strcpy(res[idx], p);
p = strtok(NULL, " ");
}
p[strlen(p)] = ' '; // Put the space back where strtok wrote the null character.
res[3] = malloc(strlen(p) + 1);
strcpy(res[3], p);
return res;
}
MsgNode* sendForm(char** res) { // Format msg before sending
struct msg_node *temp = (struct msg_node*) malloc(sizeof(struct msg_node));
temp->receiver = res[0];
temp->sender = res[1];
temp->title = res[2];
temp->content = res[3];
return temp;
}

WinDivert issue - redirecting DNS back to self on windows

I was looking at basil00's torwall, and for fun was trying to pare it down to just intercept DNS. (provide an answer back to myself of 127.0.0.1 for webfiltering purposes, learning project)
however, at this point, I have it hijacking the dns packet, but it does not return a correct address. for every "blocked" domain, it's different.
for example, I put cbc.ca in my hosts.deny file (blacklist), and it returns an address of 0.4.114.2
then blacklisting slashdot, it will return 0.4.0.1
this has been quite confusing and frustrating, and after three days of research, I am out of ideas.
Here is the code to the redirect portion of my program, which seems to be where things go awry.
(note some of the comments will be goofy as I was hacking down a program for a different purpose and haven't cleaned it up yet)
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "windivert.h"
#include "domain.h"
#include "main.h"
#include "redirect.h"
#define MAX_PACKET 4096
#define NUM_WORKERS 4
// DNS headers
#define DNS_MAX_NAME 254
struct dnshdr
{
uint16_t id;
uint16_t options;
uint16_t qdcount;
uint16_t ancount;
uint16_t nscount;
uint16_t arcount;
} __attribute__((__packed__));
struct dnsq
{
uint16_t type;
uint16_t class;
} __attribute__((__packed__));
struct dnsa
{
uint16_t name;
uint16_t type;
uint16_t class;
uint32_t ttl;
uint16_t length;
uint32_t addr;
} __attribute__((__packed__));
static DWORD redirect_worker(LPVOID arg);
static int handle_dns(HANDLE handle, PWINDIVERT_ADDRESS addr,
PWINDIVERT_IPHDR iphdr, PWINDIVERT_UDPHDR udphdr, char *data,
size_t data_len);
// State:
static bool redirect_on = false;
static HANDLE handle = INVALID_HANDLE_VALUE;
static HANDLE workers[NUM_WORKERS] = {NULL}; // Worker threads
// Send a packet asynchronously:
static void send_packet(HANDLE handle, void *packet, size_t packet_len,
PWINDIVERT_ADDRESS addr)
{
addr->Direction = WINDIVERT_DIRECTION_INBOUND;
WinDivertHelperCalcChecksums(packet, packet_len, 0);
if (!WinDivertSend(handle, packet, packet_len, addr, NULL))
debug("Send packet failed (err=%d)\n", (int)GetLastError());
}
// Start traffic redirect through Tor:
extern void redirect_start(void)
{
debug("DNS divert START\n");
if (handle != INVALID_HANDLE_VALUE)
return;
handle = WinDivertOpen(
"outbound and udp.DstPort == 53 or inbound and udp.DstPort = 53", 0, 0, 0);
// Launch threads:
redirect_on = true;
for (size_t i = 0; i < NUM_WORKERS; i++)
{
workers[i] = CreateThread(NULL, MAX_PACKET*3,
(LPTHREAD_START_ROUTINE)redirect_worker, (LPVOID)handle, 0, NULL);
if (workers[i] == NULL)
{
exit(EXIT_FAILURE);
}
}
}
// Stop traffic redirect through Tor:
extern void redirect_stop(void)
{
debug("DNS divert STOP\n");
if (handle == INVALID_HANDLE_VALUE)
return;
// Close the WinDivert handle; will cause the workers to exit.
redirect_on = false;
if (!WinDivertClose(handle))
{
exit(EXIT_FAILURE);
}
handle = INVALID_HANDLE_VALUE;
for (size_t i = 0; i < NUM_WORKERS; i++)
{
WaitForSingleObject(workers[i], INFINITE);
workers[i] = NULL;
}
}
// Redirect worker thread:
static DWORD redirect_worker(LPVOID arg)
{
HANDLE handle = (HANDLE)arg;
// Packet processing loop:
char packet[MAX_PACKET];
UINT packet_len;
WINDIVERT_ADDRESS addr;
while (redirect_on)
{
if (!WinDivertRecv(handle, packet, sizeof(packet), &addr, &packet_len))
{
// Silently ignore any error.
continue;
}
PWINDIVERT_IPHDR iphdr = NULL;
PWINDIVERT_TCPHDR tcphdr = NULL;
PWINDIVERT_UDPHDR udphdr = NULL;
PVOID data = NULL;
UINT data_len;
WinDivertHelperParsePacket(packet, packet_len, &iphdr, NULL, NULL,
NULL, &tcphdr, &udphdr, &data, &data_len);
int dnshandle = 0;
if (udphdr != NULL && ntohs(udphdr->DstPort) == 53)
dnshandle = handle_dns(handle, &addr, iphdr, udphdr, data, data_len);
if(dnshandle != 1)
{
if (!WinDivertSend(handle, packet, packet_len, &addr, NULL))
{
}
}
}
return 0;
}
// Handle DNS requests.
// NOTES:
// - If anything goes wrong, we simply drop the packet without error.
// - An alternative approach would be to let Tor resolve the address, however,
// this would be slow.
static int handle_dns(HANDLE handle, PWINDIVERT_ADDRESS addr,
PWINDIVERT_IPHDR iphdr, PWINDIVERT_UDPHDR udphdr, char *data,
size_t data_len)
{
struct dnshdr *dnshdr = (struct dnshdr *)data;
data += sizeof(struct dnshdr);
data_len -= sizeof(struct dnshdr);
char name[DNS_MAX_NAME + 8]; // 8 bytes extra.
size_t i = 0;
while (i < data_len && data[i] != 0)
{
size_t len = data[i];
if (i + len >= DNS_MAX_NAME)
return -1;
name[i++] = '.';
for (size_t j = 0; j < len; j++, i++)
name[i] = data[i];
}
name[i++] = '\0';
// Generate a fake IP address and associate it with this domain name:
uint32_t fake_addr = domain_lookup_addr(name);
if (fake_addr == 0)
{
// This domain is blocked; so ignore the request.
// Construct a query response:
size_t len = sizeof(struct dnshdr) + data_len + sizeof(struct dnsa);
if (len > 512) // Max DNS packet size.
return -1;
len += sizeof(WINDIVERT_IPHDR) + sizeof(WINDIVERT_UDPHDR) + len;
char buf[len + 8]; // 8 bytes extra.
PWINDIVERT_IPHDR riphdr = (PWINDIVERT_IPHDR)buf;
PWINDIVERT_UDPHDR rudphdr = (PWINDIVERT_UDPHDR)(riphdr + 1);
struct dnshdr *rdnshdr = (struct dnshdr *)(rudphdr + 1);
char *rdata = (char *)(rdnshdr + 1);
UINT local_ip;
DivertHelperParseIPv4Address("127.0.0.1",&local_ip);
memset(riphdr, 0, sizeof(WINDIVERT_IPHDR));
riphdr->Version = 4;
riphdr->HdrLength = sizeof(WINDIVERT_IPHDR) / sizeof(uint32_t);
riphdr->Length = htons(len);
riphdr->Id = htons(0xF00D);
WINDIVERT_IPHDR_SET_DF(riphdr, 1);
riphdr->TTL = 64;
riphdr->Protocol = IPPROTO_UDP;
riphdr->SrcAddr = iphdr->DstAddr;
riphdr->DstAddr = iphdr->SrcAddr;
memset(rudphdr, 0, sizeof(WINDIVERT_UDPHDR));
rudphdr->SrcPort = htons(53); // DNS
rudphdr->DstPort = udphdr->SrcPort;
rudphdr->Length = htons(len - sizeof(WINDIVERT_IPHDR));
rdnshdr->id = dnshdr->id;
rdnshdr->options = htons(0x8180); // Standard DNS response.
rdnshdr->qdcount = htons(0x0001);
rdnshdr->ancount = htons(0x0001);
rdnshdr->nscount = 0;
rdnshdr->arcount = 0;
memcpy(rdata, data, data_len);
struct dnsa *rdnsa = (struct dnsa *)(rdata + data_len);
rdnsa->name = htons(0xC00C);
rdnsa->type = htons(0x0001); // (A)
rdnsa->class = htons(0x0001); // (IN)
rdnsa->ttl = htonl(0x00000258) ; // 1 second
rdnsa->length = htons(0x0004);
rdnsa->addr = htonl(local_ip); // Fake address
send_packet(handle, &buf, len, addr);
debug("address: %u\n",addr->Direction);
debug("Intercept DNS %s\n", (name[0] == '.'? name+1: name));
return 1;
}
// Re-inject the matching packet.
/*
/
*/
return 0;
}
Here's the domain lookup side of it (mostly just hacked down to try to get the results I want:
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include "domain.h"
#include "main.h"
#define RATE_LIMIT 8000
#define rand16() \
(rand() & 0xFF) | ((rand() & 0xFF) << 8)
// Domain blacklist:
struct blacklist
{
size_t size;
size_t len;
char **names;
};
static struct blacklist *blacklist = NULL;
// State:
static struct name *names[UINT16_MAX] = {NULL};
static HANDLE names_lock = NULL;
// Prototypes:
static struct blacklist *domain_blacklist_read(const char *filename);
static bool domain_blacklist_lookup(struct blacklist *blacklist,
const char *name);
static int __cdecl domain_blacklist_compare_0(const void *x, const void *y);
static int domain_blacklist_compare(const char *name0, size_t len,
const char *name1);
// Initialize this module:
extern void domain_init(void)
{
// Load the domain blacklist.
blacklist = domain_blacklist_read("hosts.deny");
}
// Lookup an address given a domain name. If the name does not exist then
// create one.
extern uint32_t domain_lookup_addr(const char *name0)
{
if (name0[0] == '.')
name0++;
if (domain_blacklist_lookup(blacklist, name0))
{
debug("Block %s\n", name0);
return 0; // Blocked!
}
return;
}
// Read the blacklist file:
static struct blacklist *domain_blacklist_read(const char *filename)
{
struct blacklist *blacklist =
(struct blacklist *)malloc(sizeof(struct blacklist));
if (blacklist == NULL)
{
exit(EXIT_FAILURE);
}
blacklist->size = 0;
blacklist->len = 0;
blacklist->names = NULL;
FILE *stream = fopen(filename, "r");
if (stream == NULL)
{
return blacklist;
}
// Read blocked domains:
int c;
char buf[256];
while (true)
{
while (isspace(c = getc(stream)))
;
if (c == EOF)
break;
if (c == '#')
{
while ((c = getc(stream)) != '\n' && c != EOF)
;
continue;
}
size_t i = 0;
while (i < sizeof(buf)-1 && (c == '-' || c == '.' || isalnum(c)))
{
buf[i++] = c;
c = getc(stream);
}
if (i >= sizeof(buf)-1 || !isspace(c))
{
exit(EXIT_FAILURE);
}
buf[i] = '\0';
if (blacklist->len >= blacklist->size)
{
blacklist->size = (blacklist->size == 0? 32: 2 * blacklist->size);
blacklist->names = (char **)realloc(blacklist->names,
blacklist->size * sizeof(char *));
if (blacklist->names == NULL)
{
exit(EXIT_FAILURE);
}
}
size_t size = (i+1) * sizeof(char);
char *name = (char *)malloc(size);
if (name == NULL)
{
exit(EXIT_FAILURE);
}
for (size_t j = 0; j < i; j++)
name[j] = buf[i - 1 - j];
name[i] = '\0';
blacklist->names[blacklist->len++] = name;
}
fclose(stream);
qsort(blacklist->names, blacklist->len, sizeof(char *),
domain_blacklist_compare_0);
return blacklist;
}
// Check if a domain matches the blacklist or not:
static bool domain_blacklist_lookup(struct blacklist *blacklist,
const char *name)
{
if (blacklist->len == 0)
return false;
size_t len = strlen(name);
ssize_t lo = 0, hi = blacklist->len-1;
while (lo <= hi)
{
ssize_t mid = (lo + hi) / 2;
int cmp = domain_blacklist_compare(name, len, blacklist->names[mid]);
if (cmp > 0)
hi = mid-1;
else if (cmp < 0)
lo = mid+1;
else
return true;
}
return false;
}
// Domain compare function(s):
static int __cdecl domain_blacklist_compare_0(const void *x, const void *y)
{
const char *name0 = *(const char **)x;
const char *name1 = *(const char **)y;
return strcmp(name0, name1);
}
static int domain_blacklist_compare(const char *name0, size_t len,
const char *name1)
{
size_t i = 0;
ssize_t j = (ssize_t)len - 1;
for (; j >= 0 && name1[i] != '\0'; i++, j--)
{
int cmp = (int)name1[i] - (int)name0[j];
if (cmp != 0)
return cmp;
}
if (j < 0 && name1[i] != '\0')
return 1;
return 0;
}
any assistance is appreciated.
Also, I have uploaded the code to: Github
Thank you.
There's one of two things going on here. You're reading and writing DNS packets incorrectly, and or you're failing to convert the addresses to or from host to network order before working with them.
I'm going to bet on you reading and writing DNS packets incorrectly. I've implemented my own filtering systems using WinDivert where I was hijacking and passing all DNS traffic through my own local DNS server and I've seen these fudged addresses come out exactly as the results you're getting when I was parsing and writing DNS packets incorrectly.
The bad news is, I can't point you to a full DNS library in C/C++ as I know of none that actually make the job easier (maybe, see edits). I personally had my diversion code written in C++ with WinDivert and then use Arsoft.Tools.Net C# DNS library for actually running a local DNS server and manipulating DNS responses.
There is one project in C++ that calls itself boost::net::dns because I think the writer was hoping it would be part of boost, which it isn't and probably won't be. Avoid this library as the internal mechanism for parsing and storing multiple A Records is bugged out and broken and you'll get the same wacky results you're getting here. I tried to work with him to get it fixed but, he was only interested in blaming my code.
I'll have a gander again and update my answer if I can find a decent lib for working with DNS packets in C++. Don't try to do it yourself, we're talking about entire protocols with entire books of RFC's to do this properly yourself.
Update
As promised, here are some results from my search:
Mozilla Necko (Formerly Netlib)
http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/
C-Ares:
https://github.com/bagder/c-ares
A list of alternative libraries C-Ares compiled:
http://c-ares.haxx.se/otherlibs.html
Also, it is linux specific but pretty clean code. You might be able to pilfer through libcrafter's DNS classes and move them to your own project.
https://github.com/pellegre/libcrafter/blob/master/libcrafter/crafter/Protocols/DNS.h
Again, unless your "learning project" is understanding and recreating one of the foundational pillars of the internet, don't implement this yourself. Try and use one of the previously listed libraries to handle your DNS packets.

Any idea to extend my C code to set TOS values in IPv6 packets using IPTC library

I have the following C code to add the firewall rules
ip6tables -A OUTPUT -t filter -s 2001:db8:222:2::/64 -j DROP
C code:
struct ip6tc_handle *h;
const ip6t_chainlabel chain = "OUTPUT";
const char *tablename = "filter";
struct ip6t_entry * e;
struct ip6t_entry_target * target;
unsigned int size_ip6t_entry, size_ip6t_entry_target, total_length;
size_ip6t_entry = XT_ALIGN(sizeof(struct ip6t_entry));
size_ip6t_entry_target = 36;
total_length = size_ip6t_entry + size_ip6t_entry_target ;
//memory allocation for all structs that represent the netfilter rule we want to insert
e = calloc(1, total_length);
if(e == NULL)
{
printf("malloc failure");
exit(1);
}
e->target_offset = size_ip6t_entry ;
//next "e" struct, end of the current one
e->next_offset = total_length;
char *temps = malloc(128);
temps = "2001:db8:222:2::";
inet_pton(AF_INET6, temps, &e->ipv6.dst);
char *temps2 = malloc(128);
temps2 = "FFFF:FFFF:FFFF:FFFF::";
inet_pton(AF_INET6, temps2, &e->ipv6.dmsk);
strcpy(e->ipv6.iniface, "eth1");
//target struct
target = (struct ip6t_entry_target *) e->elems;
target->u.target_size = size_ip6t_entry_target;
strcpy(target->u.user.name, "DROP");
//All the functions, mentioned below could be found in "Querying libiptc HOWTO" manual
h = ip6tc_init(tablename);
if ( !h )
{
printf("Error initializing: %s\n", iptc_strerror(errno));
exit(errno);
}
int x = ip6tc_append_entry(chain, e, h);
if (!x)
{
printf("Error append_entry: %s\n", iptc_strerror(errno));
exit(errno);
}
printf("%s", target->data);
int y = ip6tc_commit(h);
if (!y)
{
printf("Error commit: %s\n", iptc_strerror(errno));
exit(errno);
}
exit(0);
I would like to extend this code to set the TOS values of the matched IPv6 packets as follows
ip6tables -A OUTPUT -t mangle -s 2001:db8:222:2::/64 -p icmpv6 -j TOS --set-tos 0x20
Any ideas?
I found the answer, let me share it
struct ip6tc_handle *h;
const ip6t_chainlabel chain = "OUTPUT";
const char *tablename = "mangle";
struct ip6t_entry * e;
struct ip6t_entry_target * target;
struct xt_DSCP_info *my_dscp;
unsigned int size_ip6t_entry, size_ip6t_entry_target, size_my_dscp, total_length;
size_ip6t_entry = XT_ALIGN(sizeof(struct ip6t_entry));
size_ip6t_entry_target = 36;
size_my_dscp = XT_ALIGN(sizeof(struct xt_DSCP_info));
total_length = size_ip6t_entry + size_ip6t_entry_target + size_my_dscp ;
//memory allocation for all structs that represent the netfilter rule we want to insert
e = calloc(1, total_length);
if(e == NULL)
{
printf("malloc failure");
exit(1);
}
//offsets to the other bits:
//target struct begining
e->target_offset = size_ip6t_entry ;
//next "e" struct, end of the current one
e->next_offset = total_length;
//set up packet matching rules: “-s 156.145.1.3 -d 168.220.1.9 -i eth0” part
//of our desirable rule
char *temps = malloc(128);
temps = "2001:db8:222:2::";
inet_pton(AF_INET6, temps, &e->ipv6.src);
char *temps2 = malloc(128);
temps2 = "FFFF:FFFF:FFFF:FFFF::";
inet_pton(AF_INET6, temps2, &e->ipv6.smsk);
e->ipv6.proto = 58/*IP6T_F_PROTO*/ ;
strcpy(e->ipv6.iniface, "wlan1");
//target struct
//”-j ACCEPT” part of our desirable rule
target = (struct ip6t_entry_target *) e->elems;
target->u.target_size = size_ip6t_entry_target;
strcpy(target->u.user.name, "DSCP");
my_dscp = (struct xt_DSCP_info *) target->data;
my_dscp->dscp = 8;
//All the functions, mentioned below could be found in "Querying libiptc HOWTO" manual
h = ip6tc_init(tablename);
if ( !h )
{
printf("Error initializing: %s\n", iptc_strerror(errno));
exit(errno);
}
//analogous to “iptables -A INPUT” part of our desirable rule + the rule itself
//inside of the e struct
int x = ip6tc_append_entry(chain, e, h);
if (!x)
{
printf("Error append_entry: %s\n", iptc_strerror(errno));
exit(errno);
}
printf("%s", target->data);
int y = ip6tc_commit(h);
if (!y)
{
printf("Error commit: %s\n", iptc_strerror(errno));
exit(errno);
}
exit(0);

Error when executing iptables code “Error commit: Protocol wrong type for socket”

The C code below is equivalent to the following iptables command:
ip6tables -A OUTPUT -t mangle -s 2001:db8:222:2::/64 -j MARK --set-mark 20
However, the iptables command is working fine from the command line but when I execute the code it gives the error
Error commit: Protocol wrong type for socket
although it is compiled successfully. I have also tried it with setting the DSCP value and it worked fine, so I guess something missing for the MARK module
Linux kernel 3.8.2
iptables version 1.4.12 (I also tried 1.4.21 but didn't work)
The code
struct ip6tc_handle *h;
const ip6t_chainlabel chain = "OUTPUT";
const char *tablename = "mangle";
struct ip6t_entry * e;
struct ip6t_entry_target * target;
struct xt_mark_tginfo2 *pmark;
unsigned int size_ip6t_entry, size_ip6t_entry_target, size_pmark, total_length;
size_ip6t_entry = XT_ALIGN(sizeof(struct ip6t_entry));
size_ip6t_entry_target = XT_ALIGN(sizeof(struct ip6t_entry_target));
size_pmark = XT_ALIGN(sizeof(struct xt_mark_tginfo2));
total_length = size_ip6t_entry + size_ip6t_entry_target + size_pmark ;
e = calloc(1, total_length);
if(e == NULL)
{
printf("malloc failure");
exit(1);
}
//offsets to the other bits:
//target struct begining
e->target_offset = size_ip6t_entry ;
//next "e" struct, end of the current one
e->next_offset = total_length;
char *temps = malloc(128);
temps = "2001:db8:222:2::";
inet_pton(AF_INET6, temps, &e->ipv6.src);
char *temps2 = malloc(128);
temps2 = "FFFF:FFFF:FFFF:FFFF::";
inet_pton(AF_INET6, temps2, &e->ipv6.smsk);
//e->ipv6.proto = 58 ;
//strcpy(e->ipv6.iniface, "wlan1");
//target struct
target = (struct ip6t_entry_target *) e->elems;
target->u.target_size = size_ip6t_entry_target;
strcpy(target->u.user.name, "MARK");
pmark = (struct xt_mark_tginfo2 *) target->data;
pmark->mark = 0x14;
pmark->mask = 0xff;
h = ip6tc_init(tablename);
if ( !h )
{
printf("Error initializing: %s\n", iptc_strerror(errno));
exit(errno);
}
int x = ip6tc_append_entry(chain, e, h);
if (!x)
{
printf("Error append_entry: %s\n", iptc_strerror(errno));
exit(errno);
}
printf("%s", target->data);
int y = ip6tc_commit(h);
if (!y)
{
printf("Error commit: %s\n", iptc_strerror(errno));
exit(errno);
}
exit(0);
Any ideas?
Thanks
Late reply, but would like to give a hint to prospective seekers.
Some targets(matches too) require to set correct revision, for xt_mark_tginfo2 I see it must be either 1 or 2.
Another thing is entry (ip6t_entry) flags e.g.
I have struggled with reject target (ip6t_reject_info) and I only later found out that entry flag must be set to IP6T_F_PROTO.
I'm not entirely sure, but a hint maybe to have a look at a .family from the xtables_target structure.
Good luck for iptc library fighters ;)

Resources