# [Solved] Q:  How to use a raw socket to send hand crafted...

## therealjrd

This is likely not really a gentoo issue, but y'all have been so helpful with other questions I've had, I bet somebody here will have useful ideas.

I have a wierd use case for which I'm trying to write a little software widget.  I have some devices on my network which ignore DHCP's handed out DNS server address, and just go straight to google.  The names they need to resolve are internal only, google won't resolve them.  I hacked my firewall such that if it sees DNS traffic from those devices to google, those packets get redirected to my internal server.  That works for some of them, but some reject the reply, because it comes from an internal server, not 8.8.8.8.  So to handle those, I've written a little thing which receives the DNS traffic, rewrites the sender address to be itself, forwards it to my internal DNS, captures the reply, rewrites that sender address to make it look like it came from google, and sends it back to the device.  That's the background to this little saga.

The problem I have is that when my widget sends its rewritten packet to my DNS server, nothing happens.  Wireshark reveals that the packet arrives.  It appears to have all the right values, including the IP and UDP headers.  I'm setting the checksums.  The widget uses a (PF_INET, SOCK_RAW, IPPROTO_UDP) socket for both sending and receiving.  I'm setting sockopt IP_HDRINCL to 1.  I've tried powerdns and dnsmasq on the receiving end, on the off chance that something in the app layer is silently throwing input on the floor, but neither one sees anything incoming.  It's acting like something in the network stack is disliking something about my packet, and refusing to deliver it.

Granted this is a somewhat twisted solution.  I thought it would be a quick hack, but I've spent a day on it, and I'm still missing something.  I'd be happy to hear about a better overall solution for my use case, but I'd also like to understand why my little hack isn't working.

Thanks in advance for any hints.Last edited by therealjrd on Fri Jul 16, 2021 6:45 pm; edited 1 time in total

----------

## mike155

Try to find out where your UDP packets get lost. A good point to start is

```
netstat -s -u
```

Run this command, send a DNS request and check whether the packet counters increase (UDP packets received, UDP packet receive errors).

You may want to read this article: https://www.programmersought.com/article/22141065280/

Are there any messages in the log files of your DNS servers?

----------

## therealjrd

 *mike155 wrote:*   

> Try to find out where your UDP packets get lost. A good point to start is
> 
> ```
> netstat -s -u
> ```
> ...

 

Thank you!

That command reveals UDP receive errors which correlate exactly to what I'm sending.

I read the referenced article.  Some parts don't seem relevant, but the bit about checksums does.  My current theory is that I mis-transcribed the 1's complement checksum algorithm, and am generating bogus values there.  I can follow up on that tomorrow.

----------

## Hu

There may be an easier solution.  A Linux firewall can not only filter traffic, it can also rewrite the headers.  A common use case for home users is to have the firewall NAT outbound traffic so that it appears to come from their single public IP, rather than the private range IP assigned to the individual hosts on the LAN.  Netfilter can also change the destination address, so that traffic originally destined for that public IP is instead further routed to a specific internal host.  Your use case is a bit backward of that, but the principals should hold.  I think you could use the firewall to DNAT traffic that was destined for Google to instead go to your internal host, then SNAT the responses to claim to be from Google.  If you do this, and it works, then the Linux kernel would handle the details around checksums.

Or you could raise a support case with the vendor who sold you garbage that doesn't understand DHCP properly.  :Wink:   If they can't even get that right, I wouldn't be surprised if they managed to include at least a few security vulnerabilities too.

----------

## pietinger

 *Hu wrote:*   

> I think you could use the firewall to DNAT traffic that was destined for Google to instead go to your internal host, then SNAT the responses to claim to be from Google.

 

I also think you could use DNAT, but usually you dont need an additional SNAT-rule, because all the answer packets will be also rewritten from the dnat-netfilter-rule (because netfilter uses stateful inspection).

You would need an extra SNAT if you want doing something like this: https://serverfault.com/questions/205040/accessing-the-dnatted-webserver-from-inside-the-lan

----------

## mike155

 *therealjrd wrote:*   

> That command reveals UDP receive errors which correlate exactly to what I'm sending.

 

When your widget talks to the DNS server: why do you want to calculate the checksum in your program? Use a UDP datagram socket and let the kernel calculate the checksum.

```
dns_socket_fd = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
```

----------

## therealjrd

 *mike155 wrote:*   

>  *therealjrd wrote:*   That command reveals UDP receive errors which correlate exactly to what I'm sending. 
> 
> When your widget talks to the DNS server: why do you want to calculate the checksum in your program? Use a UDP datagram socket and let the kernel calculate the checksum.
> 
> ```
> ...

 

, , , except that part of the use case is that the eventual reply packet, which goes back to the errant device, needs to have a sender address of google (8.8.8.8 or whatever).  I couldn't find a way to do that sticking strictly to regular UDP socket semantics.  Since I was going to need to rewrite some headers, I just wrote it as a man in the middle which rewrites in both directions.

I finally figured out what I was doing wrong.  The simple mistake was that I had muffed the size to the checksum of the IP header.  The trickier one was that when I read the spec the first time, I misunderstood how the UDP pseudo header needs to be set up.  It took me some more headscratching with wireshark, and reading the spec and examples some more, to get it right.  So now my widget is working.  Yay!

Hu, in principle you're right about the stupid vendors.  I'm just not optimistic about them paying attention, or caring.  I've found 2 vendors so far which do this.  I got on the phone with one of their support people.  He seemed not to understand what I was talking about, or why it was a bug.  He refused to even open a case.  

Part of why I have my network set up the way it is, is because of the security concern you cite.  Some of these devices are IP cameras.  I shudder to think what they might be doing if I gave them access to the rest of the network  :Smile: 

Thanks to all who chimed in.  Setting the title to "Solved".

----------

