Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 : #include "network.h"
10 :
11 : #ifndef HAVE_KDBCONFIG
12 : #include "kdbconfig.h"
13 : #endif
14 :
15 : /* Obtain address(es) matching host/port */
16 1053 : int elektraNetworkAddrInfo (Key * toCheck)
17 : {
18 : struct addrinfo * result;
19 : int s;
20 :
21 1053 : const Key * meta = keyGetMeta (toCheck, "check/ipaddr");
22 :
23 1053 : if (!meta) return 0; /* No check to do */
24 :
25 : struct addrinfo hints;
26 1032 : memset (&hints, 0, sizeof (struct addrinfo));
27 : hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
28 1032 : if (!strcmp (keyString (meta), "ipv4"))
29 : {
30 19 : hints.ai_family = AF_INET;
31 19 : hints.ai_flags = AI_NUMERICHOST; /* Only accept numeric hosts */
32 : }
33 1013 : else if (!strcmp (keyString (meta), "ipv6"))
34 : {
35 993 : hints.ai_family = AF_INET6;
36 993 : hints.ai_flags = AI_NUMERICHOST; /* Only accept numeric hosts */
37 : }
38 1032 : hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
39 1032 : hints.ai_protocol = 0; /* Any protocol */
40 :
41 1032 : s = getaddrinfo (keyString (toCheck), NULL, &hints, &result);
42 :
43 1032 : if (s != 0)
44 : {
45 : return s;
46 : }
47 :
48 379 : freeaddrinfo (result);
49 :
50 379 : return 0;
51 : }
52 :
53 400 : int elektraPortInfo (Key * toCheck, Key * parentKey)
54 : {
55 400 : const Key * meta = keyGetMeta (toCheck, "check/port");
56 400 : const Key * listenMeta = keyGetMeta (toCheck, "check/port/listen");
57 400 : if (!meta && !listenMeta) return 0; /* No check to do */
58 18 : char * endptr = NULL;
59 18 : long portNumber = strtol (keyString (toCheck), &endptr, 10);
60 : int portNumberNetworkByteOrder;
61 :
62 18 : if (*endptr == '\0')
63 : {
64 10 : if (portNumber < 0 || portNumber > 65535)
65 : {
66 4 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey, "Port %ld on key %s was not within 0 - 65535", portNumber,
67 : keyName (toCheck));
68 4 : return -1;
69 : }
70 6 : portNumberNetworkByteOrder = htons (portNumber);
71 : }
72 : else
73 : {
74 : struct servent * service;
75 8 : service = getservbyname (keyString (toCheck), NULL); // NULL means we accept both tcp and udp
76 8 : if (service == NULL)
77 : {
78 4 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey, "Could not find service with name %s on key %s. Reason: %s",
79 : keyString (toCheck), keyName (toCheck), strerror (errno));
80 4 : return -1;
81 : }
82 4 : portNumberNetworkByteOrder = service->s_port;
83 : }
84 :
85 10 : if (!listenMeta) return 0; /* No check to do */
86 :
87 0 : char const * hostname = "localhost";
88 :
89 : int sockfd;
90 : struct sockaddr_in serv_addr;
91 : struct hostent * server;
92 0 : sockfd = socket (AF_INET, SOCK_STREAM, 0);
93 :
94 0 : if (sockfd < 0)
95 : {
96 0 : ELEKTRA_SET_RESOURCE_ERRORF (parentKey, "Could not open a socket. Reason: %s", strerror (errno));
97 : }
98 :
99 0 : server = gethostbyname (hostname);
100 0 : if (server == NULL)
101 : {
102 0 : if (errno == HOST_NOT_FOUND)
103 : {
104 0 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey, "Could not connect to %s: No such host", hostname);
105 0 : return -1;
106 : }
107 : else
108 : {
109 0 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey, "There was an error trying to connect to host '%s'. Reason: %s",
110 : hostname, strerror (errno));
111 0 : return -1;
112 : }
113 : // TODO: Maybe consider errno == TRY_AGAIN separately and try to reconnect
114 : }
115 :
116 :
117 0 : bzero ((char *) &serv_addr, sizeof (serv_addr));
118 0 : serv_addr.sin_family = AF_INET;
119 0 : bcopy ((char *) server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);
120 :
121 0 : serv_addr.sin_port = (in_port_t) portNumberNetworkByteOrder;
122 0 : if (bind (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
123 : {
124 0 : close (sockfd);
125 0 : if (errno == EADDRINUSE)
126 : {
127 0 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey, "Port %s is already in use which was specified on key %s",
128 : keyString (toCheck), keyName (toCheck));
129 : }
130 : else
131 : {
132 0 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey,
133 : "Could not bind to port %s which was specified on key %s. Reason: %s",
134 : keyString (toCheck), keyName (toCheck), strerror (errno));
135 : }
136 : return -1;
137 : }
138 0 : close (sockfd);
139 :
140 0 : return 0;
141 : }
142 :
143 47 : int elektraNetworkGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey ELEKTRA_UNUSED)
144 : {
145 : /* configuration only */
146 : KeySet * n;
147 47 : ksAppend (returned,
148 47 : n = ksNew (30, keyNew ("system/elektra/modules/network", KEY_VALUE, "network plugin waits for your orders", KEY_END),
149 : keyNew ("system/elektra/modules/network/exports", KEY_END),
150 : keyNew ("system/elektra/modules/network/exports/get", KEY_FUNC, elektraNetworkGet, KEY_END),
151 : keyNew ("system/elektra/modules/network/exports/set", KEY_FUNC, elektraNetworkSet, KEY_END),
152 : keyNew ("system/elektra/modules/network/exports/elektraNetworkAddrInfo", KEY_FUNC, elektraNetworkAddrInfo,
153 : KEY_END),
154 : keyNew ("system/elektra/modules/network/exports/elektraPortInfo", KEY_FUNC, elektraNetworkAddrInfo, KEY_END),
155 :
156 : #include "readme_network.c"
157 :
158 : keyNew ("system/elektra/modules/network/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END));
159 47 : ksDel (n);
160 :
161 47 : return 1; /* success */
162 : }
163 :
164 1050 : int elektraNetworkSet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
165 : {
166 : /* check all keys */
167 : Key * cur;
168 1050 : ksRewind (returned);
169 2492 : while ((cur = ksNext (returned)) != 0)
170 : {
171 1053 : int s = elektraNetworkAddrInfo (cur);
172 1053 : if (s != 0)
173 : {
174 653 : const char * gaimsg = gai_strerror (s);
175 653 : char * errmsg = elektraMalloc (strlen (gaimsg) + keyGetNameSize (cur) + keyGetValueSize (cur) +
176 : sizeof ("name: value: message: "));
177 653 : strcpy (errmsg, "name: ");
178 653 : strcat (errmsg, keyName (cur));
179 653 : strcat (errmsg, " value: ");
180 653 : strcat (errmsg, keyValue (cur));
181 653 : strcat (errmsg, " message: ");
182 653 : strcat (errmsg, gaimsg);
183 653 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERROR (parentKey, errmsg);
184 653 : elektraFree (errmsg);
185 653 : return -1;
186 : }
187 400 : int p = elektraPortInfo (cur, parentKey);
188 400 : if (p != 0)
189 : {
190 : return -1;
191 : }
192 : }
193 :
194 : return 1; /* success */
195 : }
196 :
197 1169 : Plugin * ELEKTRA_PLUGIN_EXPORT
198 : {
199 : // clang-format off
200 1169 : return elektraPluginExport ("network",
201 : ELEKTRA_PLUGIN_GET, &elektraNetworkGet,
202 : ELEKTRA_PLUGIN_SET, &elektraNetworkSet,
203 : ELEKTRA_PLUGIN_END);
204 : }
205 :
|