Setting X-Forwarded-For In C

Question, I've been trying to find information for setting the X-Forwarded-For header in C programs, or basically how spoofing it works. I've seen how to do this in ruby, python, and even with curl. I tried searching Google for it, but have came up empty handed. Any links, examples or advice much appreciated.

Try searching Google "x-forwarded-for socket C"

sent from my HTC smartphone

The best I could do with "x-forwarded-for socket C" in Google was finding someone's re-write of Stunnel. While better than anything I've found so far, it didn't show how to manually set an ip for your x-forwarded-for header. Maybe its possible to end that code that way. Or maybe I'm not seeing something else?

If you're writing for CGI, headers in C are no different than in any other language -- they're just text. In some ways they're simpler, since C doesn't try to "take control" of them the way PHP does, etc.

#include <stdio.h>

int main(void) {
        // Read any POST data from stdin via fgets or other stdio calls
        // Server variables are in the environment, available via getenv, etc

        printf("Content-Type:  raw/text-only\n");
        printf("X-Forwarded-For:  ...\n");
        printf("\n");
        printf("Actual Document Content\n");

        return(0);
}
1 Like

Thank you Corona688. I meant to reply sooner, but the week got away from me. However, I'm unsure if I explained myself correctly. I'm not trying to find how to read the X-Forwarded-For from incoming requests, but more or less looking for information on how to spoof the X-Forwarded-For with outgoing requests in C. I know in Python it would be done with something like this:

import urllib2,cookielib

cj = cookielib.CookieJar() 
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
opener.addheaders = [('X-Forwarded-For','1.2.3.4'),]
resp=opener.open('http://example.com/logIP.php')

While in ruby it would be done like this:

require "net/http"
require "uri"

url = URI.parse("http://www.whatismyip.com/automation/n09230945.asp")

req = Net::HTTP::Get.new(url.path)
req.add_field("X-Forwarded-For", "0.0.0.0")

res = Net::HTTP.new(url.host, url.port).start do |http|
  http.request(req)
end

puts res.body

I haven't been able to find much information with doing this in C though.

Python in particular suffers from library-itis. If there's something which can be done, there's not just one but several conflicting libraries preinstalled for you.

C is more of a "do it yourself" language. It doesn't really lend itself to one-liners. But it gives you a level of control scripting languages don't.

Do you have wget?

#include <stdio.h>

int main(void) {
        const char *ip="1.2.3.4";
        printf("X-Forwarded-For:  %s\n", ip);
        printf("Content-Type:  text/html\n");
        printf("\n");

        // Turn over to external wget utility
        // execl never returns, your program "becomes" the command you told it to run.
        execlp("wget", "http://website.com/whatever.php", "-q" "-O" "-", NULL);
        // ...unless it can't find wget, in which case it returns an error, and so should we.
        return(1);
}

I'm not aware of a "standard" CGI library for C which everyone already has, but a quick look finds cgic: cgic: an ANSI C library for CGI Programming

You might also consider running a complete proxy such as tinyproxy.

1 Like

It seems that tinyproxy would allow for changing the X-Forwarded-For header. However, it seemed that would stop other proxies from being used. Say someone was to use proxychains to spoof the original ip of a C program running through another proxy running on port 10000, a connection would need to be made to port 10000 after hitting 8888 or whatever port tinyport is running on.

I tried finding ways for spoofing X-Forwarded-For within proxychains itself before posting here, but came up empty handed with this as well. Would you know of a good way to pass tinyproxy traffic to proxychains, another port, or proxy?

EDIT: Forgot to mention, I do have wget and know how to use X-Forwared-For with Curl already. Looking for others ways to do this with C binaries that don't use these utilities though.

There's no "native" one-liners for HTTP in C. C doesn't handle files natively, let alone HTTP. This lack of dependencies is why you can write kernels in it -- and write entire languages like ruby, python, perl, and pretty much everything you run on your computer -- but it means you have to write out what you want long-form, or install a library.

There's definitely C libraries for it, in fact you've already heard of one -- curl. Here's some source code examples for it.

1 Like

I had used libcurl once, but that link is an awesome reference! I looked through some of these while searching for one to set the header. It looks like this one is the closest example:

libcurl example - httpcustomheader.c

I suppose someone could take this part:

    /* Add a header with "blank" contents to the right of the colon. Note that
       we're then using a semicolon in the string we pass to curl! */ 
    chunk = curl_slist_append(chunk, "X-silly-header;");

And change it to something like this?:

    /* Add a header with "blank" contents to the right of the colon. Note that
       we're then using a semicolon in the string we pass to curl! */ 
    chunk = curl_slist_append(chunk, "X-Forwarded-For: 1.2.3.4;");

Not sure if I'm on the right track?

I do think you're on the right track, or a right track, there being more than one way to skin a cat.

Sorry, I got turned around. curl handles the outgoing request, not the incoming one. You'd still be doing printf("header: value\n"); and using libcurl to retrieve the data since wget wasn't sufficient.

1 Like

Well, I was actually looking for outgoing requests for this, not incoming. I did a little bit of experiementing with tcpdump and could see this being set:

$ tcpdump -vvvs 1024 -l -A | grep -i x-forward
tcpdump: listening on wlan0, link-type EN10MB (Ethernet), capture size 1024 bytes
X-Forwarded-For: 1.2.3.4;

So it appears to be working. I'm all ears if anyone thinks this is incorrect. Here is the code I modified from the previous link:

/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
 * are also available at https://curl.haxx.se/docs/copyright.html.
 *
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 * copies of the Software, and permit persons to whom the Software is
 * furnished to do so, under the terms of the COPYING file.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ***************************************************************************/ 
/* <DESC>
 * HTTP request with custom modified, removed and added headers
 * </DESC>
 */ 
#include <stdio.h>
#include <curl/curl.h>
 
int main(void)
{
  CURL *curl;
  CURLcode res;
 
  curl = curl_easy_init();
  if(curl) {
    struct curl_slist *chunk = NULL;
 
    /* Remove a header curl would otherwise add by itself */ 
    chunk = curl_slist_append(chunk, "Accept:");
 
    /* Add a custom header */ 
    chunk = curl_slist_append(chunk, "Another: yes");
 
    /* Modify a header curl otherwise adds differently */ 
    chunk = curl_slist_append(chunk, "Host: www.google.com");
 
    /* Add a header with "blank" contents to the right of the colon. Note that
       we're then using a semicolon in the string we pass to curl! */ 
    chunk = curl_slist_append(chunk, "X-Forwarded-For: 1.2.3.4;");
 
    /* set our custom set of headers */ 
    res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
 
    curl_easy_setopt(curl, CURLOPT_URL, "http://google.com");
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
 
    res = curl_easy_perform(curl);
    /* Check for errors */ 
    if(res != CURLE_OK)
      fprintf(stderr, "curl_easy_perform() failed: %s\n",
              curl_easy_strerror(res));
 
    /* always cleanup */ 
    curl_easy_cleanup(curl);
 
    /* free the custom headers */ 
    curl_slist_free_all(chunk);
  }
  return 0;
}

Appeciated the help Corona688. Much thanks!