libcurl https example error - c

I downloaded and slightly adapted this c example from the curl webpage. The test application uses my previously build curl.dll. I'm not able to connect to a https server without disabling the peer verification.
My original test application:
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL *curl = curl_easy_init();
if(curl)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
CURLcode res = curl_easy_perform(curl);
if(res != CURLE_OK)
printf ("res = %d curl_easy_perform() failed: %s\n",res, curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
curl_global_cleanup();
The output is:
* Trying XX.XXX.XXX.XX...
* TCP_NODELAY set
* Connected to example.com (XX.XXX.XXX.XX) port 443 (#0)
* ALPN, offering http/1.1
* SSL certificate problem: unable to get local issuer certificate
* Closing connection 0
res = 60 curl_easy_perform() failed: Peer certificate cannot be authenticated with given CA certificates
If I download and store a cacert.pem file from mozilla next to my exe and adapt the sample to:
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL *curl = curl_easy_init();
if(curl)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
curl_easy_setopt(curl, CURLOPT_CAPATH, ".");
CURLcode res = curl_easy_perform(curl);
if(res != CURLE_OK)
printf ("res = %d curl_easy_perform() failed: %s\n",res, curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
curl_global_cleanup();
I still get an error message
* Trying XX.XXX.XXX.XX...
* TCP_NODELAY set
* Connected to example.com (XX.XXX.XXX.XX) port 443 (#0)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: none
CApath: .
* SSL certificate problem: unable to get local issuer certificate
* Closing connection 0
res = 60 curl_easy_perform() failed: Peer certificate cannot be authenticated with given CA certificates
It is working fine if I disable peer verification.
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL *curl = curl_easy_init();
if(curl)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
curl_easy_setopt(curl, CURLOPT_CAPATH, ".");
CURLcode res = curl_easy_perform(curl);
if(res != CURLE_OK)
printf ("res = %d curl_easy_perform() failed: %s\n",res, curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
curl_global_cleanup();
Does anyone have an idea what causes this behaviour? Do I have to set the peer certificate? I haven't found a setter for this.

I solved the problem by adding the option CAINFO
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL *curl = curl_easy_init();
if(curl)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
curl_easy_setopt(curl, CURLOPT_CAINFO, "cacert.pem");
CURLcode res = curl_easy_perform(curl);
if(res != CURLE_OK)
printf ("res = %d curl_easy_perform() failed: %s\n",res, curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
curl_global_cleanup();

Related

LibCurl Telnet write data "An unknown option was passed in"

I have projector with option to communicate by TELNET. I want to send to him question about power on/off by this comamnd:
:POWR ?\r
My code:
FILE* console = fopen("/dev/tty", "w");
CURL* curl = curl_easy_init();
CURLcode res;
if (curl)
{
CURLcode res;
struct curl_slist* options;
options = curl_slist_append(NULL, "TTTYPE=:POWR ?\r");
curl_easy_setopt(curl, CURLOPT_URL, "telnet://192.168.0.90");
curl_easy_setopt(curl, CURLOPT_PORT, 1025);
curl_easy_setopt(curl, CURLOPT_TELNETOPTIONS, options);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
fprintf(console, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
curl_easy_cleanup(curl);
curl_slist_free_all(options);
fprintf(console, s.c_str());
}
As result i have:
curl_easy_perform() failed: An unknown option was passed in to libcurl
I think, that problem is with:
struct curl_slist* options;
options = curl_slist_append(NULL, "TTTYPE=:POWR ?\r");
curl_easy_setopt(curl, CURLOPT_TELNETOPTIONS, options);
But how to send data to projector and get result?
In PUTTY is ok:

Discord HTTPS POST with C

I'm trying to build a Discord API with C (libdiscord it's constantly crashing).
I have found this promosing code (found here):
#include <stdio.h> /* printf, sprintf */
#include <stdlib.h> /* exit */
#include <unistd.h> /* read, write, close */
#include <string.h> /* memcpy, memset */
#include <sys/socket.h> /* socket, connect */
#include <netinet/in.h> /* struct sockaddr_in, struct sockaddr */
#include <netdb.h> /* struct hostent, gethostbyname */
void error(const char *msg) { perror(msg); exit(0); }
int main(int argc,char *argv[])
{
/* first what are we going to send and where are we going to send it? */
int portno = 80;
char *host = "api.somesite.com";
char *message_fmt = "POST /apikey=%s&command=%s HTTP/1.0\r\n\r\n";
struct hostent *server;
struct sockaddr_in serv_addr;
int sockfd, bytes, sent, received, total;
char message[1024],response[4096];
if (argc < 3) { puts("Parameters: <apikey> <command>"); exit(0); }
/* fill in the parameters */
sprintf(message,message_fmt,argv[1],argv[2]);
printf("Request:\n%s\n",message);
/* create the socket */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) error("ERROR opening socket");
/* lookup the ip address */
server = gethostbyname(host);
if (server == NULL) error("ERROR, no such host");
/* fill in the structure */
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portno);
memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
/* connect the socket */
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
/* send the request */
total = strlen(message);
sent = 0;
do {
bytes = write(sockfd,message+sent,total-sent);
if (bytes < 0)
error("ERROR writing message to socket");
if (bytes == 0)
break;
sent+=bytes;
} while (sent < total);
/* receive the response */
memset(response,0,sizeof(response));
total = sizeof(response)-1;
received = 0;
do {
bytes = read(sockfd,response+received,total-received);
if (bytes < 0)
error("ERROR reading response from socket");
if (bytes == 0)
break;
received+=bytes;
} while (received < total);
if (received == total)
error("ERROR storing complete response from socket");
/* close the socket */
close(sockfd);
/* process response */
printf("Response:\n%s\n",response);
return 0;
}
But I need to send a header and data, according to this post (in Python):
import requests
import json
channelID = "your_id_goes_here" # enable dev mode on discord, right-click on the channel, copy ID
botToken = "your_token_here" # get from the bot page. must be a bot, not a discord app
baseURL = "https://discordapp.com/api/channels/{}/messages".format(channelID)
headers = { "Authorization":"Bot {}".format(botToken),
"User-Agent":"myBotThing (http://some.url, v0.1)",
"Content-Type":"application/json", }
message = "hello world"
POSTedJSON = json.dumps ( {"content":message} )
r = requests.post(baseURL, headers = headers, data = POSTedJSON)
I'm sorry, I don't know the protocols in detail.
I'd like to read messages too, but for now I'm OK just writing they.
UPDATE:
My new code (error 400, bad request).
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl = NULL;
CURLcode res;
const char *data = "{\"content\": \"data to send\"}";
const char *ID = "...";
const char *token = "...";
char tmp[1024];
curl = curl_easy_init();
if(curl != NULL) {
struct curl_slist *headers = NULL;
/* Remove a header curl would otherwise add by itself */
headers = curl_slist_append(headers, "Accept:");
/* Add a custom header */
sprintf(tmp, "Host: https://discordapp.com/api/channels/%s/messages", ID);
headers = curl_slist_append(headers, tmp);
sprintf(tmp, "Authorization: Bot %s", token);
headers = curl_slist_append(headers, tmp);
headers = curl_slist_append(headers, "User-Agent: myBotThing (http://some.url, v0.1)");
headers = curl_slist_append(headers, "Content-Type: application/json");
/* set our custom set of headers */
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
sprintf(tmp, "https://discordapp.com/api/channels/%s/messages", ID);
curl_easy_setopt(curl, CURLOPT_URL, tmp);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
// POST
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK) printf("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
curl_slist_free_all(headers);
}
return 0;
}

curl_easy_perform program in C

Now, after doing the changes in code I am able to send the POST resquest to SERVER and even server is sending the response. But now my program hangs at curl_easy_perform function. Do you have any idea?
curl -H "Authorization: Basic dGVzdENsaWVudDp0ZXN0U2VjcmV0" -X POST "http://x.x.x.x:8080/authservice/token?grant_type=client_credential"
My program:
struct url_data {
size_t size;
char* data;
};
static size_t write_data(char *buffer, size_t size, size_t nitems, void *userp)
{
struct url_data *data = (struct url_data *)userp;
size_t index = data->size;
size_t n = (size * nitems);
data->size += (size * nitems);
char* tmp = realloc(data->data, data->size + 1);
if(tmp) {
data->data = tmp;
} else {
if(data->data) free(data->data);
fprintf(stderr, "Failed to allocate memory.\n");
return EXIT_FAILURE;
}
memcpy(data->data + index, buffer, n);
data->data[data->size] = '\0';
return size * nitems;
}
int main(void)
{
int i = 0;
long http_code = 0;
CURL *curl;
CURLcode res;
struct curl_slist *slist=NULL;
struct url_data data;
data.size = 0;
data.data = (char*) malloc(4096); /* reasonable size initial buffer */
bzero(data.data, 4096);
//curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://x.x.x.x:8080/authservice/token?grant_type=client_credential");
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
slist = curl_slist_append(slist, "Authorization: Basic dGVzdENsaWVudDp0ZXN0U2VjcmV0");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
slist = curl_slist_append(slist, "Content-Type:application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
slist = curl_slist_append(slist, "Content-Length: 0");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
slist = curl_slist_append(slist, "Expect:");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
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));
} else {
fprintf(stderr, "Data:[%s] Ret:[%s]\n", data.data, curl_easy_strerror(res));
}
res = curl_easy_getinfo (curl, CURLINFO_HTTP_CODE, &http_code);
printf("http_code:%ld\n", http_code);
/* always cleanup */
curl_easy_cleanup(curl);
if(data.data) free(data.data);
curl_slist_free_all(slist);
}
//curl_global_cleanup();
return 0;
}
Output:
* About to connect() to x.x.x.x port 8080 (#0)
* Trying x.x.x.x...
* connected
* Connected to x.x.x.x (x.x.x.x) port 8080 (#0)
> POST /authservice/token?grant_type=client_credential HTTP/1.1
User-Agent: libcurl-agent/1.0
Host: x.x.x.x:8080
Accept: */*
Authorization: Basic dGVzdENsaWVudDp0ZXN0U2VjcmV0
Content-Type:application/json
Content-Length: 0

How to set cookie in curl post request in c

I have set the cookie into HTTP header in this way.
.....
CURL *curl;
CURLcode res;
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: application/x-www-form-urlencoded");
headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
headers = curl_slist_append(headers, "charsets: utf-8");
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl,CURLOPT_HTTPHEADER,headers);
curl_easy_setopt(curl, CURLOPT_URL,"http://localhost:9763/addApp.jag");
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS,reqbody);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, body_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA,&cookiec);
curl_easy_setopt(curl, CURLOPT_COOKIE,cookie);
res=curl_easy_perform(curl);
......
In server side when I retrieved post data they seem to be null. But when I check from Wireshark actually those post data are sent. But when I remove
curl_easy_setopt(curl, CURLOPT_COOKIE,cookie);
I can access the post data in the server side. If I make any mistake in my post request please correct me.
Actually it little bit complicated to find answer for this. Because when I set the cookie it should be excluded \r\n characters in cookie value which is coming from server side. If somebody want to do this here is the sample code
struct response_data *makeCURLRequest(char* reqbody,char* cookie,int memorySize,char* url){
CURL *curl;
struct url_data data;
data.size = 0;
data.data = malloc(memorySize);
if(NULL == data.data) {
fprintf(stderr, "Failed to allocate memory.\n");
return NULL;
}
struct site_cookie cookiec;
cookiec.size=0;
cookiec.cookie=malloc(256);
if(NULL == cookiec.cookie) {
fprintf(stderr, "Failed to allocate memory.\n");
return NULL;
}
struct response_data* res_data;
res_data=malloc(sizeof(struct response_data));
res_data->res_body=malloc(1000);
res_data->res_cookie=malloc(256);
if(NULL == res_data->res_body || NULL==res_data->res_cookie) {
fprintf(stderr, "Failed to allocate memory.\n");
return NULL;
}
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: Subscription/x-www-form-urlencoded");
headers = curl_slist_append(headers, "Content-Type: Subscription/x-www-form-urlencoded");
headers = curl_slist_append(headers, "charsets: utf-8");
data.data[0] = '\0';
cookiec.cookie[0]= '\0';
res_data->res_body[0]='\0';
res_data->res_cookie[0]='\0';
buf_t *buf = buf_size(NULL, BUFFER_SIZE);
CURLcode res;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_URL,url);
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS,reqbody);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fetch_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, buf);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA,&cookiec);
curl_easy_setopt(curl, CURLOPT_COOKIE,cookie);
res=curl_easy_perform(curl);
if(res != CURLE_OK){
fprintf(stderr, "curl_easy_perform() failed: %s\n",curl_easy_strerror(res));
return NULL;
}
curl_easy_cleanup(curl);
char *jsonstr = buf_tostr(buf);
free(buf->data);
free(buf);
strcpy(res_data->res_body,jsonstr);
strcpy(res_data->res_cookie,cookiec.cookie);
return res_data;
}
full source code can be found here https://github.com/GPrathap/REST_API_in_C/blob/master/libs/curlreq.c

Sending raw http headers

I have the following raw HTTP request:
GET http://www.google.ie/ HTTP/1.1
Host: www.google.ie
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:5.0) Gecko/20100101 Firefox/5.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encod...
I'm trying to send this from my localhost. Could someone point me in the right direction as to how I might do this in C or C++?
I'm currently looking at sockets, but it's not really working.
int sockfdi, portnoi, ni;
struct sockaddr_in serv_addri;
struct hostent *serveri;
portnoi =80;
sockfdi = socket(AF_INET, SOCK_STREAM, 0);
if (sockfdi < 0){
error("***ERROR opening socket");
}
serveri = gethostbyname("172.16.1.218");
if (serveri == NULL){
fprintf(stderr,"***ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addri, sizeof(serv_addri));
serv_addri.sin_family = AF_INET;
bcopy((char *)serveri->h_addr, (char *)&serv_addri.sin_addr.s_addr, serveri->h_length);
serv_addri.sin_port = htons(portnoi);
if (connect(sockfdi,(struct sockaddr *) &serv_addri,sizeof(serv_addri)) < 0){
error("***ERROR connecting");
}
printf("Please enter the message: ");
bzero(buffer,256);
You could try using libcurl instead of sockets:
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
CURLcode res;
struct curl_slist *headers = NULL;
curl = curl_easy_init();
if(curl) {
headers = curl_slist_append(headers, "Host: www.google.ie");
headers = curl_slist_append(headers, "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:5.0) Gecko/20100101 Firefox/5.0");
headers = curl_slist_append(headers, "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
headers = curl_slist_append(headers, "Accept-Language: en-us,en;q=0.5");
/* Add more headers here */
curl_easy_setopt(curl, CURLOPT_URL, "http://www.google.ie/");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
res = curl_easy_perform(curl);
/* always cleanup */
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
return 0;
}

Resources