Dovecot Failed to init dict: dict redis: Invalid IP - redis

I'm using Dovecot v2.3.9.3. By looking to the dovecot docs I see that specification for Redis is the following:
redis:param=value:param2=value2:...
Here one of the parameters is host: Redis server host (default: 127.0.0.1).
In my configuration I have specified uri = redis:host=redis:port=6379:
Feb 23 20:48:32 auth: Fatal: dict /etc/dovecot/dovecot-dict-auth.conf.ext: Failed to init dict: dict redis: Invalid IP: redis
redis hostname on my server resolves to the IP without any problem:
# getent hosts redis
192.168.48.2 redis redis
Is there a way to use hostname (maybe some hidden setting which enables the resolution), or they just bluntly did not implement a support for that? :/

TL;DR
Dovecot redis dict driver accepts undocumented parameter path in which you can specify the unix socket. You may then create a proxy to the hostname redis serving on the tcp port 6379 via the unix socket /run/redis.soc:
socat unix-listen:/run/redis.soc,reuseaddr,fork,perm=0644,user=dovecot tcp:redis:6379 &
Dovecot config becomes:
# Dictionary URI
uri = redis:path=/run/redis.soc
The following is my analysis of the problem. I don't code in C, so my understanding was limited.
Code which covers my error (Invalid IP: redis) is the following:
} else if (str_begins(*args, "host=")) {
if (net_addr2ip(*args+5, &ip) < 0) {
*error_r = t_strdup_printf("Invalid IP: %s",
*args+5);
ret = -1;
}
}
It relies on the net_addr2ip function which depends on the net_addr2ip_inet4_fast. Both of these functions do not seem to do, what their names are suggesting (they do not turn addr to ip):
static bool net_addr2ip_inet4_fast(const char *addr, struct ip_addr *ip)
{
uint8_t *saddr = (void *)&ip->u.ip4.s_addr;
unsigned int i, num;
if (str_parse_uint(addr, &num, &addr) < 0)
return FALSE;
if (*addr == '\0' && num <= 0xffffffff) {
/* single-number IPv4 address */
ip->u.ip4.s_addr = htonl(num);
ip->family = AF_INET;
return TRUE;
}
/* try to parse as a.b.c.d */
i = 0;
for (;;) {
if (num >= 256)
return FALSE;
saddr[i] = num;
if (i == 3)
break;
i++;
if (*addr != '.')
return FALSE;
addr++;
if (str_parse_uint(addr, &num, &addr) < 0)
return FALSE;
}
if (*addr != '\0')
return FALSE;
ip->family = AF_INET;
return TRUE;
}
int net_addr2ip(const char *addr, struct ip_addr *ip)
{
int ret;
if (net_addr2ip_inet4_fast(addr, ip))
return 0;
if (strchr(addr, ':') != NULL) {
/* IPv6 */
T_BEGIN {
if (addr[0] == '[') {
/* allow [ipv6 addr] */
size_t len = strlen(addr);
if (addr[len-1] == ']')
addr = t_strndup(addr+1, len-2);
}
ret = inet_pton(AF_INET6, addr, &ip->u.ip6);
} T_END;
if (ret == 0)
return -1;
ip->family = AF_INET6;
} else {
/* IPv4 */
if (inet_aton(addr, &ip->u.ip4) == 0)
return -1;
ip->family = AF_INET;
}
return 0;
}
Therefore host parameter in dovecot's redis dict driver cannot be anything else but an IP address ¯_(ツ)_/¯

Related

UDP directed broadcast (WinSock2) failure

Let me start by saying this is my first foray into the world of C after 20+ years of assembly programming for PLCs and MicroControllers.
I'm trying to send a UDP datagram to the network broadcast address, in this particular case, 192.168.1.255.
The error I'm getting is a bind failure with error code 10049 (from WSAGetLastError()). As you can see from the attached code, I've created the socket, populated sockaddr_in, and setsockopt() to SO_BROADCAST.
For the life of me I can't figure out what I'm doing wrong and any pointers would be gratefully received.
iResult = WSAStartup(MAKEWORD(2, 2), &wsaTxData);
if (iResult != NO_ERROR)
{
WSAErrorString("WSAStartup for TX failed");
return(-1);
}
XPLMDebugString("UDP Server: WSAStartup TX complete.\n");
if ((BeaconSocket = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
WSAErrorString("UDP Server: Could not create BECN socket");
return(-1);
}
// setup the sockaddr_in structure
//
si_beacon.sin_family = AF_INET;
si_beacon.sin_addr.s_addr = inet_addr("192.168.1.255");
si_beacon.sin_port = htons(_UDP_TX_PORT);
// setup to broadcast
//
char so_broadcast_enabled = '1';
if (setsockopt(BeaconSocket, SOL_SOCKET, SO_BROADCAST, &so_broadcast_enabled, sizeof(so_broadcast_enabled)) == SOCKET_ERROR) {
WSAErrorString("Error in setting Broadcast option");
closesocket(BeaconSocket);
return(-1);
}
// bind our socket
//
if (bind(BeaconSocket, (struct sockaddr *)&si_beacon, sizeof(si_beacon)) == SOCKET_ERROR)
{
char buf[256];
WSAErrorString("Bind to socket for UDP beacon failed");
sprintf(buf, "Port %u, address %s\n", ntohs(si_beacon.sin_port), inet_ntoa(si_beacon.sin_addr));
XPLMDebugString(buf);
return(-1);
}
// start the UDP beacon
//
udp_becn_thread_id = CreateThread(NULL, 0, BeaconThread, NULL, 0, NULL);
if (!udp_becn_thread_id) {
WSAErrorString("UDP Server: Error starting UDP Beacon");
return (-1);
}
XPLMDebugString("UDP Server: bind complete. beacon ACTIVE.\n");
return(0);
The issue is the IP address itself.
I copied the code to my computer (changed it a bit to get it to compile) and I got the error:
UDP Server: WSAStartup TX complete.
Bind to socket for UDP beacon failed
Port 47977, address 192.168.1.255
I then changed the line:
si_beacon.sin_addr.s_addr = inet_addr("192.168.1.255");
To
si_beacon.sin_addr.s_addr = inet_addr("192.168.0.127");
And when I ran it again, everything worked:
UDP Server: WSAStartup TX complete.
Done successfully
The issue is that the "bind" address needs to be your computers address on the local network. Not the remote client.
Another alternative is to use the address:
si_beacon.sin_addr.s_addr = inet_addr("0.0.0.0");
which binds to all network interfaces on the computer at once.
For reference, here's the version of the code that I used:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <WinSock2.h>
#include <WS2tcpip.h> // For inet_pton
#pragma comment(lib, "ws2_32.lib")
int main()
{
{
WSADATA wsaTxData;
memset(&wsaTxData, 0, sizeof(WSADATA));
const int iResult = WSAStartup(MAKEWORD(2, 2), &wsaTxData);
if (iResult != NO_ERROR)
{
printf("%s", "WSAStartup for TX failed.\n");
return -1;
}
printf("%s", "UDP Server: WSAStartup TX complete.\n");
}
SOCKET BeaconSocket;
memset(&BeaconSocket, 0, sizeof(SOCKET));
if ((BeaconSocket = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
printf("%s", "UDP Server: Could not create BECN socket\n");
return -1;
}
// setup the sockaddr_in structure
//
sockaddr_in si_beacon;
memset(&si_beacon, 0, sizeof(sockaddr_in));
si_beacon.sin_family = AF_INET;
si_beacon.sin_addr.s_addr = inet_addr("0.0.0.0");
const unsigned short port_num = 0xbb69;
si_beacon.sin_port = htons(port_num);
// setup to broadcast
//
char so_broadcast_enabled = '1';
if (setsockopt(BeaconSocket, SOL_SOCKET, SO_BROADCAST, &so_broadcast_enabled, sizeof(so_broadcast_enabled)) == SOCKET_ERROR) {
printf("%s", "Error in setting Broadcast option\n");
closesocket(BeaconSocket);
return(-1);
}
// bind our socket
//
if (bind(BeaconSocket, (struct sockaddr*)&si_beacon, sizeof(si_beacon)) == SOCKET_ERROR)
{
char buf[256];
printf("%s", "Bind to socket for UDP beacon failed\n");
sprintf_s(buf, "Port %u, address %s\n", ntohs(si_beacon.sin_port), inet_ntoa(si_beacon.sin_addr));
printf("%s", buf);
return(-1);
}
printf("%s", "Done successfully");
return 0;
}

OpenSSL 1.0.1 SSL_read() function return 0 byte on certain https Websites

I'm trying to make a https client by openssl 1.0.1u that can visit websites with ssl protocol.
When visiting most of https websites (like google.com, yahoo.com, facebook.com, ...), it works well and the home page content is returned. However, there are certain websites (relatively small websites), the server returns me 0 bytes, here are some details:
I use SSLv23_method() to create my openssl context:
this->_sslContext = SSL_CTX_new(SSLv23_method()); // SSLv23_method: Negotiate highest available SSL/TLS version
Then I found that in the following calling sequence (listed forwardly):
(ssl_lib.c) SSL_read(SSL *s, void *buf, int num) ---->
(s3_lib.c) ssl3_read(SSL *s, void *buf, int len) ---->
(s3_lib.c) ssl3_read_internal(SSL *s, void *buf, int len, int peek) ---->
(s3_pkt.c) int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
With some website (failed case), the function SSL_read() return 0 bytes because inside the function ssl3_read_bytes(), I got a alert_descr set to SSL_AD_CLOSE_NOTIFY then the function simply return 0, here is the source code:
...
if (alert_level == SSL3_AL_WARNING)
{
s->s3->warn_alert = alert_descr;
if (alert_descr == SSL_AD_CLOSE_NOTIFY) {
s->shutdown |= SSL_RECEIVED_SHUTDOWN;
return (0);
}
Anyone can give me any hint to fix this problem? Thanks.
=== UPDATE ===
Upon Steffen Ullrich's suggestion, I post source code that sends request / gets respone. My small experimental https client is composed of Socket and SSLSocket classes and a helper WebpageFetcher class. The function WebpageFetcher::fetchPage is used to send the https request and get the respond from private function WebpageFetcher::_getResponse():
wchar_t * WebpageFetcher::fetchPage(wchar_t * url, int port, bool useSSL)
{
wchar_t * response = NULL;
Socket * socket = Socket::createSocket(false, useSSL);
if (socket == nullptr)
{
response = String(L"Connection failed. Unable to create a SSLSocket!\n").toCharArray();
return response;
}
if (!socket->connect(url, port))//Connection failed
{
response = String(L"Connection failed. Possible reason: Wrong server URL or port.\n").toCharArray();
}
else //Connection succeeded
{
//Send request to server socket
static const char * REQUEST = "GET / \r\n\r\n";
static const int REQUEST_LEN = (const int)strlen(REQUEST);
socket->send((void *)REQUEST, REQUEST_LEN);
//Get the response from server
response = _getResponse(socket);
socket->shutDown();
socket->close();
}
delete socket;
return response;
}
// ============================================================================
wchar_t * WebpageFetcher::_getResponse(Socket * socket)
{
static const int READSIZE = 1024; //Reading buffer size, the larger the better performance
int responseBufferSize = READSIZE + 1;
char * readBuf = new char[READSIZE];
char * responseBuf = new char[responseBufferSize];
int bytesReceived;
int totalBytesReceived = 0;
while ((bytesReceived = socket->recv(readBuf, READSIZE)) > 0)
{
// Check if need to expand responseBuf size
if (totalBytesReceived + bytesReceived >= responseBufferSize)//No enough capacity, expand the response buffer
{
responseBufferSize += READSIZE;
char * tempBuf = new char[responseBufferSize];
memcpy(tempBuf, responseBuf, totalBytesReceived);
delete[] responseBuf;
responseBuf = tempBuf; //Response buffer expanded
}
// Append data from readBuf
memcpy(responseBuf + totalBytesReceived, readBuf, bytesReceived);
totalBytesReceived += bytesReceived;
responseBuf[totalBytesReceived] = '\0';
}
wchar_t * response = (wchar_t *)(totalBytesReceived == 0 ? //Generate the response as a C wide string
String(L"Received nothing from server. Possible reason: Wrong port.\n").toCharArray() :
StringUtil::charsToWchars(responseBuf));
delete[] readBuf;
delete[] responseBuf;
return response;
}
I passed argument useSSL with true when call factory function Socket::createSocket() so that the socket I got is a SSLSocket instance, which overrides the default functions connect(), _send() and _recv() to let openssl to do the actual job. Here is the constructor of my SSLSocket class, which derives from class Socket:
SSLSocket::SSLSocket(bool isServerSocket, int port, int socketType, int socketProtocol, int uOptions, wchar_t * strBindingAddress, wchar_t * cerPath, wchar_t * keyPath, wchar_t * keyPass) :
Socket(isServerSocket, port, socketType, socketProtocol, uOptions, strBindingAddress)
{
// Register the error strings
SSL_load_error_strings();
// Register the available ciphers and digests
SSL_library_init();
// Create an SSL_CTX structure by choosing a SSL/TLS protocol version
this->_sslContext = SSL_CTX_new(SSLv23_method()); // Use SSL 2 or SSL 3
// Create an SSL struct (client only, server does not need one)
this->_sslHandle = (this->_isServer ? NULL : SSL_new(this->_sslContext));
bool success = false;
if (!this->_isServer) // is Client socket
{
success = (this->_sslHandle != NULL);
}
else if (cerPath != NULL && keyPath != NULL) // is Server socket
{
success = ......
}
if (!success)
this->close();
}
And the followings are the functions override the virtual functions in parent class Socket, which lets openssl to do the relevant job:
bool SSLSocket::connect(wchar_t * strDestination, int port, int timeout)
{
SocketAddress socketAddress(strDestination, port);
return this->connect(&socketAddress, timeout);
}
bool SSLSocket::connect(SocketAddress * sockAddress, int timeout)
{
bool success =
(this->_sslHandle != NULL &&
Socket::connect(sockAddress, timeout) && // Regular TCP connection
SSL_set_fd(this->_sslHandle, (int)this->_hSocket) == 1 && // Connect the SSL struct to our connection
SSL_connect(this->_sslHandle) == 1); // Initiate SSL handshake
if (!success)
this->close();
return success;
}
int SSLSocket::_recv(void * lpBuffer, int size, int flags)
{
MonitorLock cs(&_mutex);
return SSL_read(this->_sslHandle, lpBuffer, size);
}
int SSLSocket::_send(const void * lpBuffer, int size, int flags)
{
return SSL_write(this->_sslHandle, lpBuffer, size);
}

A bind socket request gives a EADDRNOTAVAIL

I have a small C program where I am trying to bind to a socket at a certain ip:port. Here it the program -
int main ()
{
int udp_fd = -1;
struct sockaddr_in sockaddr;
char *ip = (char *)"xx.yyy.zzz.aaa";
int port = 1234;
udp_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (udp_fd == -1) {
printf("Could not create socket\n");
return -1;
}
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = inet_addr(ip);
sockaddr.sin_port = htons(port);
if (bind(udp_fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) == -1) {
printf("Could not bind to %s: %d: %d: %d\n", ip, port, errno, udp_fd);
return -1;
}
if (fcntl(udp_fd, F_SETFL, O_NONBLOCK | O_ASYNC) < 0) {
printf("Error setting socket as non-blocking \n");
return -1;
}
return 0;
}
This fails with EADDRNOTAVAIL
define EADDRNOTAVAIL 99 /* Cannot assign requested address */
I try to connect to the same server from another device that is on the same network as the other device that fails the bind and it is successful.
There are no firewalls enabled on the failing device.
You are trying to bind your socket to a non-local IP address.
You don't generally need to bind to a specific IP address at all. Change:
sockaddr.sin_addr.s_addr = inet_addr(ip);
to
sockaddr.sin_addr.s_addr = INADDR_ANY;

browser connection with server socket in c

i'm a beginner in network programming and i have a project in which i have to create a system explorer. That means that i will have the ability to write a http request with a directory in a browser and if the connection with the server is succesfull, the files from the above directory will open.
int main(int argc, char** argv)
{
typedef struct tcpip_connection
{
int connfd;
struct sockaddr_in peer_addr;
} tcpip_connection;
int s_socket, *fd, port;
char buffer[256];
struct sockaddr_in lis_addr;
struct sockaddr_in peer_addr;
int sopt = 1, n;
s_socket=socket(AF_INET, SOCK_STREAM, 0);
if(s_socket<0){
printf("error: the socket was not created!");
}
if(setsockopt(s_socket , SOL_SOCKET, SO_REUSEADDR, &sopt, sizeof(sopt))){
printf("Setsokopt error!");
}
memset(&lis_addr, 0, sizeof(lis_addr));
lis_addr.sin_family = AF_INET;
lis_addr.sin_addr.s_addr = htonl(INADDR_ANY);
lis_addr.sin_port = htons(port);
if ( bind( s_socket, (struct sockaddr*) &lis_addr, sizeof(lis_addr) ) < 0 ){
perror(NULL);
exit(-1);
}
if(listen(s_socket,15)<0){
perror("server.listen");
}
socklen_t peer_addrlen;
while(1){
if((fd = malloc(sizeof(int))) == NULL){
fprintf(stderr, "Out of memory\n");
abort();
}
*fd=accept(s_socket, (struct sockaddr*)&peer_addr,&peer_addrlen);
if(fd<0){
if( errno==EINTR /* Call interrupted by signal */
|| errno==ECONNABORTED /* connection was aborted */
|| errno==EMFILE /* per-process limit of open fds */
|| errno==ENFILE /* system-wide limit of open fds */
|| errno==ENOBUFS /* no space for socket buffers */
|| errno==ENOMEM /* no space for socket buffers */
|| errno==EPERM /* Firewall blocked the connection */
)
continue;
}
}
if(errno == EBADF)
break; /* return, the server_socket is closed */
}
bzero(buffer,1024);
n = read(*fd,buffer,1023);
if (n < 0)
{
perror("ERROR reading from socket");
exit(1);
}
printf("Here is the message: %s\n",buffer);
/* Write a response to the client
n = write(*fd,"I got your message",18);
if (n < 0)
{
perror("ERROR writing to socket");
exit(1);
}
return 0;*/
}
I don't know if there is anything wrong with my code, but the main problem is that i don't know how to make the browser connect with the server. Is there anything i have to write in the browser or do i have to add some extra code?
You forgot to initialize the port variable. Try setting port = 8080 before you call bind and listen.
Then, in your browser, go to http://localhost:8080/ and it should connect.

Unable to capture the IPv6 multicast traffic for Windows 8

Following is the function I wrote to capture IPv6 multicast data coming on multicast address ff02::1 and port 9154.
This code works fine on Windows Vista and Windows 7. But I am unable to capture the same traffic for Windows 8 (none of the winsock functions returns error for Win8).
Using netstat I am able to verify that my application is using this port.
Can any one help?
void func()
{
int multicastChannel = 0;
char multicastIP[] = "FF02::1";
char multicastPort[] = "9154";
ADDRINFO* multicastAddr = NULL;
ADDRINFO* localAddr = NULL;
ADDRINFO hints = { 0 };
struct ipv6_mreq multicastRequest6;
hints.ai_family = PF_UNSPEC;
hints.ai_flags = AI_NUMERICHOST;
if ( getaddrinfo(multicastIP, NULL, &hints, &multicastAddr) != 0 )
{
printf("getaddrinfo() failed");
return;
}
hints.ai_family = multicastAddr->ai_family;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
if ( getaddrinfo(NULL, multicastPort, &hints, &localAddr) != 0 )
{
printf("getaddrinfo() failed");
return;
}
multicastChannel = socket(localAddr->ai_family, localAddr->ai_socktype, 0);
if ( bind(multicastChannel, localAddr->ai_addr, localAddr->ai_addrlen) != 0 )
{
printf("bind() failed");
return;
}
memcpy(&multicastRequest6.ipv6mr_multiaddr,
&((struct sockaddr_in6*)(multicastAddr->ai_addr))->sin6_addr,
sizeof(multicastRequest6.ipv6mr_multiaddr));
multicastRequest6.ipv6mr_interface = 0;
if ( setsockopt(multicastChannel,
IPPROTO_IPV6,
IPV6_ADD_MEMBERSHIP,
(char*) &multicastRequest6,
sizeof(multicastRequest6)) != 0 )
{
ERROR_ReportError("setsockopt() failed");
}
freeaddrinfo(localAddr);
freeaddrinfo(multicastAddr);
ioctlsocket(multicastChannel, FIONBIO, &arg);
sockaddr_in6 fromAddr;
while(1)
{
read = recvfrom(multicastChannel,
data,
1500,
0,
(struct sockaddr*)&fromAddr,
&sizeof(sockaddr_in6);
if (read > 0) {
function();
}
}
}