LIBSSDP
 All Classes Files Functions Variables Typedefs Macros
ssdp_cache.c
Go to the documentation of this file.
1 
7 #include <arpa/inet.h>
8 #include <errno.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 
13 #include "common_definitions.h"
14 #include "configuration.h"
15 #include "log.h"
16 #include "net_utils.h"
17 #include "socket_helpers.h"
18 #include "ssdp_message.h"
19 #include "ssdp_cache.h"
20 #include "ssdp_message.h"
22 
30 static BOOL create_plain_text_message(char *results, int buffer_size,
31  ssdp_message_s *ssdp_message) {
32  int buffer_used = 0, count = 0;
33  ssdp_custom_field_s *cf = NULL;
34 
35  if(ssdp_message->custom_fields) {
36  cf = ssdp_message->custom_fields->first;
37  }
38 
39  buffer_used += snprintf(results + buffer_used,
40  buffer_size - buffer_used,
41  "Time received: %s\n",
42  ssdp_message->datetime);
43  buffer_used += snprintf(results + buffer_used,
44  buffer_size - buffer_used,
45  "Origin-MAC: %s\n",
46  (ssdp_message->mac != NULL ? ssdp_message->mac :
47  "(Could not be determined)"));
48  buffer_used += snprintf(results + buffer_used,
49  buffer_size - buffer_used,
50  "Origin-IP: %s\nMessage length: %d Bytes\n",
51  ssdp_message->ip,
52  ssdp_message->message_length);
53  buffer_used += snprintf(results + buffer_used,
54  buffer_size - buffer_used,
55  "Request: %s\nProtocol: %s\n",
56  ssdp_message->request,
57  ssdp_message->protocol);
58 
59  while(cf) {
60  buffer_used += snprintf(results + buffer_used,
61  buffer_size - buffer_used,
62  "Custom field[%d][%s]: %s\n",
63  count,
64  cf->name,
65  cf->contents);
66  count++;
67  cf = cf->next;
68  }
69 
70  count = 0;
71  ssdp_header_s *ssdp_headers = ssdp_message->headers;
72  while(ssdp_headers) {
73  buffer_used += snprintf(results + buffer_used,
74  buffer_size - buffer_used,
75  "Header[%d][type:%d;%s]: %s\n",
76  count, ssdp_headers->type,
77  get_header_string(ssdp_headers->type, ssdp_headers),
78  ssdp_headers->contents);
79  ssdp_headers = ssdp_headers->next;
80  count++;
81  }
82 
83  return TRUE;
84 }
85 
98 static int send_stuff(const char *url, const char *data,
99  const struct sockaddr_storage *da, int port, int timeout,
101 
102  if(url == NULL || strlen(url) < 1) {
103  PRINT_ERROR("send_stuff(): url not set");
104  return 1;
105  }
106 
107  /* Create socket */
108  PRINT_DEBUG("send_stuff(): creating socket");
109 
110  socket_conf_s sock_conf = {
111  conf->use_ipv6,
112  FALSE,
113  FALSE,
114  conf->interface,
115  conf->ip,
116  NULL,
117  NULL,
118  0,
119  FALSE,
120  0,
121  FALSE,
122  conf->ttl,
123  conf->enable_loopback,
124  timeout,
125  timeout
126  };
127 
128  SOCKET send_sock = setup_socket(&sock_conf);
129  if(send_sock == SOCKET_ERROR) {
130  PRINT_ERROR("send_stuff(): %s", strerror(errno));
131  return errno;
132  }
133 
134  /* Setup socket destination address */
135  PRINT_DEBUG("send_stuff(): setting up socket address");
136 
137  if(da->ss_family == AF_INET) {
138  struct sockaddr_in *da_ipv4 = (struct sockaddr_in *)da;
139  da_ipv4->sin_port = htons(port);
140  }
141  else {
142  struct sockaddr_in6 *da_ipv6 = (struct sockaddr_in6 *)da;
143  da_ipv6->sin6_port = htons(port);
144  }
145 
146  #ifdef DEBUG___
147  char tmp_ip[IPv6_STR_MAX_SIZE];
148  get_ip_from_sock_address(da, tmp_ip);
149  PRINT_DEBUG("send_stuff(): connecting to destination (%s; ss_family = "
150  "%s [%d])", tmp_ip, (da->ss_family == AF_INET ? "AF_INET" : "AF_INET6"),
151  da->ss_family);
152  #endif
153 
154  /* Connect socket to destination */
155  if(connect(send_sock, (struct sockaddr*)da, sizeof(struct sockaddr)) ==
156  SOCKET_ERROR) {
157  PRINT_ERROR("send_stuff(): connect(): %d, %s", errno, strerror(errno));
158  close(send_sock);
159  return errno;
160  }
161 
162  /*
163  POST </path/file.html> HTTP/1.0\r\n
164  Host: <own_ip>\r\n
165  User-Agent: abused-<X>\r\n
166  \r\n
167  */
168  char *ip = (char *)malloc(sizeof(char) * IPv6_STR_MAX_SIZE);
169  memset(ip, '\0', IPv6_STR_MAX_SIZE);
170  inet_ntop(da->ss_family, (da->ss_family == AF_INET ?
171  (void *)&((struct sockaddr_in *)da)->sin_addr :
172  (void *)&((struct sockaddr_in6 *)da)->sin6_addr), ip, IPv6_STR_MAX_SIZE);
173 
174  int request_size = strlen(data) + 150;
175  char *request = (char *)malloc(sizeof(char) * request_size);
176  memset(request, '\0', request_size);
177 
178  int used_length = 0;
179  used_length = snprintf(request + used_length,
180  request_size - used_length,
181  "POST %s HTTP/1.1\r\n", url);
182  used_length += snprintf(request + used_length,
183  request_size - used_length,
184  "Host: %s\r\n", ip);
185  used_length += snprintf(request + used_length,
186  request_size - used_length,
187  "Connection: close\r\n");
188  used_length += snprintf(request + used_length,
189  request_size - used_length,
190  "User-Agent: abused-%s\r\n", ABUSED_VERSION);
191  used_length += snprintf(request + used_length,
192  request_size - used_length,
193  "Content-type: text/xml\r\n");
194  used_length += snprintf(request + used_length,
195  request_size - used_length,
196  "Content-length: %d\r\n\r\n", (int)strlen(data));
197  used_length += snprintf(request + used_length,
198  request_size - used_length,
199  "%s\r\n\r\n", data);
200  free(ip);
201 
202  PRINT_DEBUG("send_stuff(): sending string:\n%s", request);
203  int bytes = send(send_sock, request, strlen(request), 0);
204  free(request);
205  if(bytes < 1) {
206  PRINT_ERROR("send_stuff(): Failed forwarding message (%d bytes sent)",
207  bytes);
208  close(send_sock);
209  return 1;
210  }
211 
212  PRINT_DEBUG("send_stuff(): sent %d bytes", bytes);
213  int response_size = 10240; // 10KB
214  char *response = (char *)malloc(sizeof(char) * response_size);
215  if (!response) {
216  PRINT_ERROR("Allocation failed: %s", strerror(errno));
217  return 1;
218  }
219  memset(response, '\0', response_size);
220 
221  int all_bytes = 0;
222  do {
223  bytes = recv(send_sock, response + all_bytes, response_size - all_bytes, 0);
224  all_bytes += bytes;
225  } while(bytes > 0);
226 
227  PRINT_DEBUG("send_stuff(): received %d bytes:\n%s", all_bytes, response);
228 
229  free(response);
230  PRINT_DEBUG("send_stuff(): closing socket");
231  close(send_sock);
232 
233  return 0;
234 }
235 
241 static void free_ssdp_cache(ssdp_cache_s **ssdp_cache_pointer) {
242  ssdp_cache_s *ssdp_cache = NULL;
243  ssdp_cache_s *next_cache = NULL;
244 
245  /* Sanity check */
246  if (!ssdp_cache_pointer) {
247  PRINT_ERROR("No ssdp cache list given");
248  return;
249  }
250 
251  /* If there is any elements in the list */
252  if(NULL != *ssdp_cache_pointer) {
253 
254  /* Make life easier */
255  ssdp_cache = *ssdp_cache_pointer;
256 
257  /* Start from the first element */
258  ssdp_cache = ssdp_cache->first;
259 
260  /* Free counter */
261  free(ssdp_cache->ssdp_messages_count);
262 
263  /* Loop through elements and free them */
264  do {
265 
266  PRINT_DEBUG("Freeing one cache element");
267 
268  /* Free the ssdp_message */
269  if(NULL != ssdp_cache->ssdp_message) {
270  free_ssdp_message(&ssdp_cache->ssdp_message);
271  }
272 
273  /* Point to the next element in the list */
274  next_cache = ssdp_cache->next;
275  free(ssdp_cache);
276  ssdp_cache = next_cache;
277 
278  } while(NULL != ssdp_cache);
279 
280  /* Finally set the list to NULL */
281  *ssdp_cache_pointer = NULL;
282  }
283  #ifdef __DEBUG
284  else {
285  PRINT_DEBUG("*ssdp_cache_pointer is NULL");
286  }
287  #endif
288 }
289 
291  ssdp_message_s **ssdp_message_pointer) {
292  ssdp_message_s *ssdp_message = *ssdp_message_pointer;
293  ssdp_cache_s *ssdp_cache = NULL;
294 
295  /* Sanity check */
296  if (!ssdp_cache_pointer) {
297  PRINT_ERROR("No ssdp cache list given");
298  return FALSE;
299  }
300 
301  /* Initialize the list if needed */
302  if (!(*ssdp_cache_pointer)) {
303  PRINT_DEBUG("Initializing the SSDP cache");
304  *ssdp_cache_pointer = (ssdp_cache_s *) malloc(sizeof(ssdp_cache_s));
305  if (!(*ssdp_cache_pointer)) {
306  PRINT_ERROR("Failed to allocate memory for the ssdp cache list");
307  return FALSE;
308  }
309  memset(*ssdp_cache_pointer, 0, sizeof(ssdp_cache_s));
310 
311  /* Set the ->first to point to this element */
312  (*ssdp_cache_pointer)->first = *ssdp_cache_pointer;
313 
314  /* Set ->new to point to NULL */
315  (*ssdp_cache_pointer)->next = NULL;
316 
317  /* Set the counter to 0 */
318  (*ssdp_cache_pointer)->ssdp_messages_count =
319  (unsigned int *)malloc(sizeof(unsigned int));
320  *(*ssdp_cache_pointer)->ssdp_messages_count = 0;
321  }
322  else {
323 
324  /* Point to the begining of the cache list */
325  ssdp_cache = (*ssdp_cache_pointer)->first;
326 
327  /* Check for duplicate and update it if found */
328  while (ssdp_cache) {
329  if (0 == strcmp(ssdp_message->ip, ssdp_cache->ssdp_message->ip)) {
330  /* Found a duplicate, update existing instead */
331  PRINT_DEBUG("Found duplicate SSDP message (IP '%s'), updating",
332  ssdp_cache->ssdp_message->ip);
333  strcpy(ssdp_cache->ssdp_message->datetime, ssdp_message->datetime);
334  if(strlen(ssdp_cache->ssdp_message->mac) < 1) {
335  PRINT_DEBUG("Field MAC was empty, updating to '%s'",
336  ssdp_message->mac);
337  strcpy(ssdp_cache->ssdp_message->mac, ssdp_message->mac);
338  }
339  // TODO: make it update all existing fields before freeing it...
340  PRINT_DEBUG("Trowing away the duplicate ssdp message and using "
341  "existing instead");
342  free_ssdp_message(ssdp_message_pointer);
343  /* Point to the existing ssdp message */
344  *ssdp_message_pointer = ssdp_cache->ssdp_message;
345  return TRUE;
346  }
347  ssdp_cache = ssdp_cache->next;
348  }
349 
350  }
351 
352  /* Point to the passed position */
353  ssdp_cache = *ssdp_cache_pointer;
354 
355  /* Make sure we are at the end of the linked list
356  and move to last if needed*/
357  if(NULL != ssdp_cache->next) {
358  PRINT_DEBUG("Given SSDP Cache list is not pointing to the last element");
359  while(NULL != ssdp_cache->next) {
360  ssdp_cache = ssdp_cache->next;
361  }
362  PRINT_DEBUG("Moved to the last element in the cache list");
363  }
364 
365  /* If working on an preexisting cache list
366  then create a new element in the list,
367  set the 'first' field to the first element
368  and move to the new element */
369  if(NULL != ssdp_cache->ssdp_message) {
370  PRINT_DEBUG("Creating a new element in the SSDP cache list");
371  ssdp_cache->next = (ssdp_cache_s *) malloc(sizeof(ssdp_cache_s));
372  memset(ssdp_cache->next, 0, sizeof(ssdp_cache_s));
373  ssdp_cache->next->first = ssdp_cache->first;
374  ssdp_cache->next->next = NULL;
375  ssdp_cache->next->ssdp_messages_count = ssdp_cache->ssdp_messages_count;
376  ssdp_cache = ssdp_cache->next;
377  }
378 
379  /* Point to the ssdp_message from the element
380  and increase the counter */
381  (*ssdp_cache->ssdp_messages_count)++;
382  PRINT_DEBUG("SSDP cache counter increased to %d",
383  *ssdp_cache->ssdp_messages_count);
384  ssdp_cache->ssdp_message = ssdp_message;
385 
386  /* Set the passed ssdp_cache to point to the last element */
387  *ssdp_cache_pointer = ssdp_cache;
388 
389  return TRUE;
390 }
391 
393  const char *url, struct sockaddr_storage *sockaddr_recipient, int port,
394  int timeout) {
395  ssdp_cache_s *ssdp_cache = *ssdp_cache_pointer;
396  int ssdp_list_size = *ssdp_cache->ssdp_messages_count * XML_BUFFER_SIZE;
397  char ssdp_list[ssdp_list_size];
398 
399  /* If -j then convert all messages to one JSON blob */
400  if (conf->json_output) {
401  if(cache_to_json(ssdp_cache, ssdp_list, ssdp_list_size) < 1) {
402  PRINT_ERROR("Failed creating JSON blob from ssdp cache");
403  return FALSE;
404  }
405  }
406 
407  /* If -x then convert all messages to one XML blob */
408  if (conf->xml_output) {
409  if(cache_to_xml(ssdp_cache, ssdp_list, ssdp_list_size) < 1) {
410  PRINT_ERROR("Failed creating XML blob from ssdp cache");
411  return FALSE;
412  }
413  }
414 
415  // TODO: make it create a list instead of single plain message
416  else if (!create_plain_text_message(ssdp_list, XML_BUFFER_SIZE,
417  ssdp_cache->ssdp_message)) {
418  PRINT_ERROR("Failed creating plain-text message");
419  return FALSE;
420  }
421 
422  /* Send the converted cache list to the recipient (-a) */
423  if (send_stuff(url, ssdp_list, sockaddr_recipient, port, timeout, conf)) {
424  PRINT_WARN("Failed to send SSDP list to the specified forward address");
425  }
426 
427  /* When the ssdp_cache has been sent
428  then free/empty the cache list */
429  free_ssdp_cache(ssdp_cache_pointer);
430 
431  return TRUE;
432 }
433 
#define IPv6_STR_MAX_SIZE
SOCKET setup_socket(socket_conf_s *conf)
unsigned int cache_to_json(ssdp_cache_s *ssdp_cache, char *json_buffer, unsigned int json_buffer_size)
const char * get_header_string(const unsigned int header_type, const ssdp_header_s *header)
Definition: ssdp_message.c:402
char ip[IPv6_STR_MAX_SIZE]
Definition: configuration.h:18
static void free_ssdp_cache(ssdp_cache_s **ssdp_cache_pointer)
Definition: ssdp_cache.c:241
struct ssdp_custom_field_struct * custom_fields
Definition: ssdp_message.h:112
int SOCKET
char interface[IPv6_STR_MAX_SIZE]
Definition: configuration.h:16
unsigned char type
Definition: ssdp_message.h:58
static int send_stuff(const char *url, const char *data, const struct sockaddr_storage *da, int port, int timeout, configuration_s *conf)
Definition: ssdp_cache.c:98
struct ssdp_header_struct * next
Definition: ssdp_message.h:66
unsigned int cache_to_xml(ssdp_cache_s *ssdp_cache, char *xml_buffer, unsigned int xml_buffer_size)
struct ssdp_header_struct * headers
Definition: ssdp_message.h:108
BOOL flush_ssdp_cache(configuration_s *conf, ssdp_cache_s **ssdp_cache_pointer, const char *url, struct sockaddr_storage *sockaddr_recipient, int port, int timeout)
Definition: ssdp_cache.c:392
void free_ssdp_message(ssdp_message_s **message_pointer)
Definition: ssdp_message.c:608
BOOL add_ssdp_message_to_cache(ssdp_cache_s **ssdp_cache_pointer, ssdp_message_s **ssdp_message_pointer)
Definition: ssdp_cache.c:290
struct ssdp_cache_struct * next
Definition: ssdp_cache.h:27
#define TRUE
#define FALSE
struct ssdp_custom_field_struct * first
Definition: ssdp_message.h:76
struct ssdp_cache_struct * first
Definition: ssdp_cache.h:23
unsigned char ttl
Definition: configuration.h:50
ssdp_message_s * ssdp_message
Definition: ssdp_cache.h:25
#define XML_BUFFER_SIZE
Definition: ssdp_message.h:16
#define ABUSED_VERSION
int BOOL
static configuration_s conf
Definition: main.c:73
#define SOCKET_ERROR
unsigned int * ssdp_messages_count
Definition: ssdp_cache.h:29
static BOOL create_plain_text_message(char *results, int buffer_size, ssdp_message_s *ssdp_message)
Definition: ssdp_cache.c:30
char * get_ip_from_sock_address(const struct sockaddr_storage *saddr, char *ip_buffer)
Definition: net_utils.c:621
struct ssdp_custom_field_struct * next
Definition: ssdp_message.h:78