I want to set up TCP server on windows and TCP client on ESP32. Main idea is to send String to ESP32 change it and send it back to server, but I'm really new with all of this stuff and got stuck on setting up TCP client on ESP32. Examples or references would be really helpful.
int create_ipv4_socket()
{
struct addrinfo hints;
struct addrinfo *res;
struct in_addr *addr;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
int err = getaddrinfo(UDP_IPV4_ADDR, TCP_PORT, &hints, &res);
if(err != 0 || res == NULL) {
printf("DNS lookup failed err=%d res=%p\n", err, res);
return -1;
}
/* Code to print the resolved IP.
Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */
addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
printf("DNS lookup succeeded. IP=%s\n", inet_ntoa(*addr));
l_sock = socket(res->ai_family, res->ai_socktype, 0);
if(l_sock < 0) {
printf("... Failed to allocate socket.\n");
freeaddrinfo(res);
return -1;
}
struct timeval to;
to.tv_sec = 2;
to.tv_usec = 0;
setsockopt(l_sock,SOL_SOCKET,SO_SNDTIMEO,&to,sizeof(to));
if(connect(l_sock, res->ai_addr, res->ai_addrlen) != 0) {
printf("... socket connect failed errno=%d\n", errno);
close(l_sock);
freeaddrinfo(res);
return -1;
}
printf("... connected\n");
freeaddrinfo(res);
// All set, socket is configured for sending and receiving
return l_sock;
}
From this forum https://www.esp32.com/viewtopic.php?t=5965
How do you communicate with your ESP? if you communicate through UART, just send him AT command he need by writing on the UART port:
"AT+CIPSTATUS\r\n"
and then wait for his response.
If you are connected to your ESP32 directly with your computer, just use putty and directly send AT command to it.
A non exhaustive list of AT's command can be found here:
https://www.espressif.com/sites/default/files/documentation/esp32_at_instruction_set_and_examples_en.pdf
I want to add following snat and dnat rules using nftables:
nft add rule nat post udp sport 29000 ip saddr 192.168.101.102 udp dport 40000 ip daddr 192.168.101.102 snat 192.168.101.55:35000
nft add rule nat pre udp sport 29000 ip saddr 192.168.101.103 udp dport 32000 ip daddr 192.168.101.55 dnat 192.168.101.102:40000
Here, pre and post is name of the chains in the nat table and I have added those with the following commands:
nft add table nat
nft add chain nat pre { type nat hook prerouting priority 0 \; }
nft add chain nat post { type nat hook postrouting priority 100 \; }
I have already checked it with the nft command and it is working perfectly.
I want to achieve the same with API approach from my application. There are some examples and test program provided in the libnftnl library. From the reference of nft-rule-add.c and nft-expr_nat-test.c I have made a test application for the same as follows:
/* Packets coming from */
#define SADDR "192.168.1.103"
#define SPORT 29000
/* Packets coming to (the machine on which nat happen) */
#define DADDR "192.168.101.55"
#define DPORT 32000
/* Packets should go from (the machine on which nat happen) */
#define SNATADDR DADDR
#define SNATPORT 35000
/* Packets should go to */
#define DNATADDR SADDR
#define DNATPORT 38000
static void add_payload(struct nftnl_rule *rRule, uint32_t base, uint32_t dreg,
uint32_t offset, uint32_t len)
{
struct nftnl_expr *tExpression = nftnl_expr_alloc("payload");
if (tExpression == NULL) {
perror("expr payload oom");
exit(EXIT_FAILURE);
}
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_PAYLOAD_BASE, base);
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_PAYLOAD_DREG, dreg);
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_PAYLOAD_OFFSET, offset);
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_PAYLOAD_LEN, len);
nftnl_rule_add_expr(rRule, tExpression);
}
static void add_cmp(struct nftnl_rule *rRule, uint32_t sreg, uint32_t op,
const void *data, uint32_t data_len)
{
struct nftnl_expr *tExpression = nftnl_expr_alloc("cmp");
if (tExpression == NULL) {
perror("expr cmp oom");
exit(EXIT_FAILURE);
}
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_CMP_SREG, sreg);
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_CMP_OP, op);
nftnl_expr_set(tExpression, NFTNL_EXPR_CMP_DATA, data, data_len);
nftnl_rule_add_expr(rRule, tExpression);
}
static void add_nat(struct nftnl_rule *rRule, uint32_t sreg,
const void *ip, uint32_t ip_len,
const void *port, uint32_t port_len)
{
struct nftnl_expr *tExpression = nftnl_expr_alloc("nat");
if (tExpression == NULL) {
perror("expr cmp oom");
exit(EXIT_FAILURE);
}
/* Performing snat */
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_NAT_TYPE, NFT_NAT_SNAT);
/* Nat family IPv4 */
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_NAT_FAMILY, NFPROTO_IPV4);
/* Don't know what to do with these four calls */
/* How to add IP address and port that should be used in snat */
// nftnl_expr_set_u32(tExpression, NFTNL_EXPR_NAT_REG_ADDR_MIN, NFT_REG_1);
// nftnl_expr_set_u32(tExpression, NFTNL_EXPR_NAT_REG_ADDR_MAX, NFT_REG_3);
// nftnl_expr_set_u32(tExpression, NFTNL_EXPR_NAT_REG_PROTO_MIN, 0x6124385);
// nftnl_expr_set_u32(tExpression, NFTNL_EXPR_NAT_REG_PROTO_MAX, 0x2153846);
nftnl_rule_add_expr(rRule, tExpression);
}
static struct nftnl_rule *setup_rule(uint8_t family, const char *table,
const char *chain, const char *handle)
{
struct nftnl_rule *rule = NULL;
uint8_t proto = 0;
uint16_t dport = 0, sport = 0, sNatPort = 0, dNatPort = 0;
uint8_t saddr[sizeof(struct in6_addr)]; /* Packets coming from */
uint8_t daddr[sizeof(struct in6_addr)]; /* Packets coming to (the machine on which nat happens) */
uint8_t snataddr[sizeof(struct in6_addr)]; /* Packets should go from (the machine on which nat happens) */
uint8_t dnataddr[sizeof(struct in6_addr)]; /* Packets should go to */
uint64_t handle_num;
rule = nftnl_rule_alloc();
if (rule == NULL) {
perror("OOM");
exit(EXIT_FAILURE);
}
nftnl_rule_set(rule, NFTNL_RULE_TABLE, table);
nftnl_rule_set(rule, NFTNL_RULE_CHAIN, chain);
nftnl_rule_set_u32(rule, NFTNL_RULE_FAMILY, family);
if (handle != NULL) {
handle_num = atoll(handle);
nftnl_rule_set_u64(rule, NFTNL_RULE_POSITION, handle_num);
}
/* Declaring tcp port or udp port */
proto = IPPROTO_UDP;
add_payload(rule, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
offsetof(struct iphdr, protocol), sizeof(uint8_t));
add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &proto, sizeof(uint8_t));
/* Declaring dport */
dport = htons(DPORT);
add_payload(rule, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1,
offsetof(struct udphdr, dest), sizeof(uint16_t));
add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &dport, sizeof(uint16_t));
/* Declaring dest ip */
add_payload(rule, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
offsetof(struct iphdr, daddr), sizeof(daddr));
inet_pton(AF_INET, DADDR, daddr);
add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, daddr, sizeof(daddr));
/* Declaring sport */
sport = htons(SPORT);
add_payload(rule, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1,
offsetof(struct udphdr, source), sizeof(uint16_t));
add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &sport, sizeof(uint16_t));
/* Declaring src ip */
add_payload(rule, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
offsetof(struct iphdr, saddr), sizeof(saddr));
inet_pton(AF_INET, SADDR, saddr);
add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, saddr, sizeof(saddr));
/* Addding snat params */
inet_pton(AF_INET, SNATADDR, snataddr);
sNatPort = htons(SNATPORT);
add_nat(rule, NFT_REG_1, snataddr, sizeof(snataddr), &sNatPort, sizeof(uint16_t));
return rule;
}
int main(int argc, char *argv[])
{
struct mnl_socket *nl;
struct nftnl_rule *r;
struct nlmsghdr *nlh;
struct mnl_nlmsg_batch *batch;
uint8_t family;
char buf[MNL_SOCKET_BUFFER_SIZE];
uint32_t seq = time(NULL);
int ret, batching;
if (argc < 4 || argc > 5) {
fprintf(stderr, "Usage: %s <family> <table> <chain>\n", argv[0]);
exit(EXIT_FAILURE);
}
if (strcmp(argv[1], "ip") == 0)
family = NFPROTO_IPV4;
else if (strcmp(argv[1], "ip6") == 0)
family = NFPROTO_IPV6;
else {
fprintf(stderr, "Unknown family: ip, ip6\n");
exit(EXIT_FAILURE);
}
// Now creating rule
if (argc != 5)
r = setup_rule(family, argv[2], argv[3], NULL);
else
r = setup_rule(family, argv[2], argv[3], argv[4]);
// Now adding rule through mnl socket
nl = mnl_socket_open(NETLINK_NETFILTER);
if (nl == NULL) {
perror("mnl_socket_open");
exit(EXIT_FAILURE);
}
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
perror("mnl_socket_bind");
exit(EXIT_FAILURE);
}
batching = nftnl_batch_is_supported();
if (batching < 0) {
perror("cannot talk to nfnetlink");
exit(EXIT_FAILURE);
}
batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
if (batching) {
nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
mnl_nlmsg_batch_next(batch);
}
nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
NFT_MSG_NEWRULE,
nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY),
NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK, seq++);
nftnl_rule_nlmsg_build_payload(nlh, r);
nftnl_rule_free(r);
mnl_nlmsg_batch_next(batch);
if (batching) {
nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
mnl_nlmsg_batch_next(batch);
}
ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch),
mnl_nlmsg_batch_size(batch));
if (ret == -1) {
perror("mnl_socket_sendto");
exit(EXIT_FAILURE);
}
mnl_nlmsg_batch_stop(batch);
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
if (ret == -1) {
perror("mnl_socket_recvfrom");
exit(EXIT_FAILURE);
}
ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(nl), NULL, NULL);
if (ret < 0) {
perror("mnl_cb_run");
exit(EXIT_FAILURE);
}
mnl_socket_close(nl);
return EXIT_SUCCESS;
}
Here, main() function calls setup_rule() where whole rule is built. setup_rule() calls add_nat() where expression for snat is built. The IP and Port that should be used for snat or dnat are passed as args to add_nat().
As I understand, the phylosophy of building a rule is that a rule is built with various expressions. In add_nat() an expression is built for doing snat and that's where I start to fumble. Don't know what to do with NFTNL_EXPR_NAT_REG_ADDR_MIN and NFTNL_EXPR_NAT_REG_PROTO_MIN kind of macros. How to pass IP Address and Port Address which will be used in snat or dnat.
I run the above test application as follows:
./application ip nat pre
And with the following command
nft list table nat -a
got the output as follows:
table ip nat {
chain pre {
type nat hook prerouting priority 0; policy accept;
udp dport 32000 ip daddr 192.168.101.55 #nh,160,96 541307071 udp sport 29000 ip saddr 192.168.1.103 ip daddr 0.0.0.0 #nh,160,64 3293205175 snat to # handle 250
} # handle 33
chain post {
type nat hook postrouting priority 100; policy accept;
} # handle 34
} # handle 0
May be the approach is wrong, but, as shown above, it displayed snat to in the end. And that gives me the hope that this is the way forward. I also digged in the nftables utility code but to no avail.
So to list all queries:
How to add snat or dnat rules with nftable apis?
What is with NFT_REG_1? How these registers should be used and where it should be used?
What is written after # in the output of the nft list table nat -a command? When I apply rules with nft command than it does not show info after # in the output of nft list table
Also, there is an extra ip addr 0.0.0.0 displayed in the output of nft list table nat -a command. Where does that get added?
I'm trying to assign the IP Address of the device to a String variable. When I use Serial.println(Ethernet.localIP()) to test it displays the IP Address in octets. If I use String(Ethernet.localIP()); then it displays it as a decimal.
Is there a way to assign the octet format to a variable?
String MyIpAddress;
void StartNetwork()
{
Print("Initializing Network");
if (Ethernet.begin(mac) == 0) {
while (1) {
Print("Failed to configure Ethernet using DHCP");
delay(10000);
}
}
Serial.println(Ethernet.localIP()); //displays: 192.168.80.134
MyIpAddress = String(Ethernet.localIP());
Serial.println(MyIpAddress); //displays: 2253433024
}
Turns out that the IPAddress property is an array. One simple way to display the IP address is as follows:
String DisplayAddress(IPAddress address)
{
return String(address[0]) + "." +
String(address[1]) + "." +
String(address[2]) + "." +
String(address[3]);
}
A more lightweight approach is this:
char* ip2CharArray(IPAddress ip) {
static char a[16];
sprintf(a, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
return a;
}
An IP address is, at maximum, 15 characters long, so a 16-character buffer suffices. Making it static ensures memory lifetime, so you can return it safely.
Another approach: the character buffer may be provided by the caller:
void ip2CharArray(IPAddress ip, char* buf) {
sprintf(buf, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
}
just use toString()
display.drawString(0, 30, WiFi.localIP().toString());
I use buildroot cross toolchain to compile Raspberry application from my computer (Ubuntu X86).
I'm developping a TCP serveur that allows a connection on 5003 (0x138B) TCP port number. When I'm start the server, that's right but my server wait a connection on 35603 (0x8B13) TCP port number (check with netstat -a).
It seems to be an endianness problem but I don't know how to resolve.
Can you help me please?
Thanks.
thanks for your answer.
I agree it's very strange. I don't think the code is the problem. It's working well on other platform.
Please find the code below:
/*Create the server */
int CreateServeur (unsigned short port, int *sock_srv, int nb_connect)
{
int l_ret = -1;
struct sockaddr_in l_srv_addr;
/* address initialisation */
printf("creation serveur port %i\n", port);
memset ((char*) &l_srv_addr,0, sizeof (struct sockaddr_in));
l_srv_addr.sin_family = PF_INET;
l_srv_addr.sin_port = port;
l_srv_addr.sin_addr.s_addr = htonl (INADDR_ANY);
/* main socket creation */
if ((*sock_srv = socket (PF_INET, SOCK_STREAM, 0)) <= 0)
{
printf("server socket creation error");
}
else
{
if (bind (*sock_srv, (struct sockaddr *) &l_srv_addr, sizeof (struct sockaddr_in)) == -1)
{
close (*sock_srv);
printf("bind socket error");
}
else
{
if (listen (*sock_srv, nb_connect) == ERROR)
{
close (*sock_srv);
printf("listen socket error");
}
else
{
l_ret = 0;
}
}
}
return (l_ret);
}
This function doesn't return any error. The first log (printf("creation serveur port %i\n", port);) display the good port (5003) but the server wait connexion on port 35603 (netstat -a).
If it's not a endianness problem, I don't understand.
I am trying to write a multicast client on a machine with two NICs, and I can't make it work. I can see with a sniffer that once I start the program the NIC (eth4) start receiving the multicast datagrams, However, I can't recieve() any in my program.
When running "tshark -i eth4 -R udp.port==xxx (multicast port)"
I get:
1059.435483 y.y.y.y. (some ip) -> z.z.z.z (multicast ip, not my eth4 NIC IP) UDP Source port: kkk (some other port) Destination port: xxx (multicast port)
Searched the web for some examples/explanations, but it seems like I do what everybody else does. Any help will be appreciated. (anything to do with route/iptables/code?)
bool connectionManager::sendMulticastJoinRequest()
{
struct sockaddr_in localSock;
struct ip_mreqn group;
char* mc_addr_str = SystemManager::Instance()->getTCP_IP_CHT();
char* local_addr_str = SystemManager::Instance()->getlocal_IP_TOLA();
int port = SystemManager::Instance()->getTCP_Port_CHT();
/* Create a datagram socket on which to receive. */
CHT_UDP_Feed_sock = socket(AF_INET, SOCK_DGRAM, 0);
if(CHT_UDP_Feed_sock < 0)
{
perror("Opening datagram socket error");
return false;
}
/* application to receive copies of the multicast datagrams. */
{
int reuse = 1;
if(setsockopt(CHT_UDP_Feed_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
{
perror("Setting SO_REUSEADDR error");
close(CHT_UDP_Feed_sock);
return false;
}
}
/* Bind to the proper port number with the IP address */
/* specified as INADDR_ANY. */
memset((char *) &localSock, 0, sizeof(localSock));
localSock.sin_family = AF_INET;
localSock.sin_port = htons(port);
localSock.sin_addr.s_addr =inet_addr(local_addr_str); // htonl(INADDR_ANY); //
if(bind(CHT_UDP_Feed_sock, (struct sockaddr*)&localSock, sizeof(localSock)))
{
perror("Binding datagram socket error");
close(CHT_UDP_Feed_sock);
return false;
}
/* Join the multicast group mc_addr_str on the local local_addr_str */
/* interface. Note that this IP_ADD_MEMBERSHIP option must be */
/* called for each local interface over which the multicast */
/* datagrams are to be received. */
group.imr_ifindex = if_nametoindex("eth4");
if (setsockopt(CHT_UDP_Feed_sock, SOL_SOCKET, SO_BINDTODEVICE, "eth4", 5) < 0)
return false;
group.imr_multiaddr.s_addr = inet_addr(mc_addr_str);
group.imr_address.s_addr = htonl(INADDR_ANY); //also tried inet_addr(local_addr_str); instead
if(setsockopt(CHT_UDP_Feed_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0)
{
perror("Adding multicast group error");
close(CHT_UDP_Feed_sock);
return false;
}
// Read from the socket.
char databuf[1024];
int datalen = sizeof(databuf);
if(read(CHT_UDP_Feed_sock, databuf, datalen) < 0)
{
perror("Reading datagram message error");
close(CHT_UDP_Feed_sock);
return false;
}
else
{
printf("Reading datagram message...OK.\n");
printf("The message from multicast server is: \"%s\"\n", databuf);
}
return true;
}
Just a thought, (I've not done much work with multicast), but could it be because you're binding to a specific IP address? The socket could be only accepting packets destined for it's bound IP address and rejecting the multicast ones?
Well, there is some time ago since I didn't play with multicast. Don't you need root/admin rights to use it? did you enable them when launching your program?