LIBSSDP
 All Classes Files Functions Variables Typedefs Macros
ssdp_listener.c
Go to the documentation of this file.
1 
7 #include <errno.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/socket.h> /* struct sockaddr_storage */
11 #include <unistd.h> /* close() */
12 
13 #include "common_definitions.h"
14 #include "configuration.h"
15 #include "log.h"
16 #include "net_definitions.h"
17 #include "net_utils.h"
18 #include "socket_helpers.h"
19 #include "ssdp_filter.h"
20 #include "ssdp_cache.h"
21 #include "ssdp_cache_display.h"
23 #include "ssdp_common.h"
24 #include "ssdp_listener.h"
25 #include "ssdp_message.h"
26 #include "ssdp_static_defs.h"
27 
29 #define LISTEN_QUEUE_LENGTH 5
30 
34 #define SSDP_PASSIVE_LISTENER_TIMEOUT 10
35 
39 #define SSDP_ACTIVE_LISTENER_TIMEOUT 2
40 
54 static int ssdp_listener_init(ssdp_listener_s *listener,
55  configuration_s *conf, BOOL is_active, int port, int recv_timeout) {
56  PRINT_DEBUG("ssdp_listener_init()");
57  SOCKET sock = SOCKET_ERROR;
58 
59  if (!listener) {
60  PRINT_ERROR("No listener specified");
61  return 1;
62  }
63 
64  memset(listener, 0, sizeof *listener);
65 
66  /* If set, parse the forwarder address */
67  if (conf->forward_address) {
68  if (parse_address(conf->forward_address, &listener->forwarder)) {
69  PRINT_WARN("Errnoeous forward address");
70  return 1;
71  }
72  }
73 
74  socket_conf_s sock_conf = {
75  conf->use_ipv6, // BOOL is_ipv6
76  TRUE, // BOOL is_udp
77  is_active, // BOOL is_multicast
78  conf->interface, // char interface
79  conf->ip, // the IP we want to bind to
80  NULL, // struct sockaddr_storage *sa
81  SSDP_ADDR, // const char *ip
82  port, // int port
83  TRUE, // BOOL is_server
84  LISTEN_QUEUE_LENGTH, // the length of the listen queue
85  FALSE, // BOOL keepalive
86  conf->ttl, // time to live (router hops)
87  conf->enable_loopback,// see own messages on multicast
88  0, // set the rend timeout for the socker (0 = default)
89  recv_timeout // set the receive timeout for the socket
90  };
91 
92  sock = setup_socket(&sock_conf);
93  if (sock == SOCKET_ERROR) {
94  PRINT_DEBUG("[%d] %s", errno, strerror(errno));
95  return errno;
96  }
97 
98  listener->sock = sock;
99  PRINT_DEBUG("ssdp_listener has been initialized");
100 
101  return 0;
102 }
103 
106  PRINT_DEBUG("ssdp_passive_listener_init()");
107  return ssdp_listener_init(listener, conf, TRUE, SSDP_PORT,
109 }
110 
112  configuration_s *conf, int port) {
113  PRINT_DEBUG("ssdp_active_listener_init()");
114  return ssdp_listener_init(listener, conf, FALSE, port,
116 }
117 
119 
120  if (!listener)
121  return;
122 
123  if (listener->sock > 0)
124  close(listener->sock);
125 }
126 
128  ssdp_recv_node_s *recv_node) {
129  PRINT_DEBUG("ssdp_listener_read()");
130  struct sockaddr_storage recv_addr;
131  size_t addr_size = sizeof recv_addr;
132 
133  recv_node->recv_bytes = recvfrom(listener->sock, recv_node->recv_data,
134  SSDP_RECV_DATA_LEN, 0, (struct sockaddr *)&recv_addr,
135  (socklen_t *)&addr_size);
136 
137  if (recv_node->recv_bytes > 0) {
138  get_ip_from_sock_address(&recv_addr, recv_node->from_ip);
139  get_mac_address_from_socket(listener->sock, &recv_addr, NULL,
140  recv_node->from_mac);
141  }
142 }
143 
145  PRINT_DEBUG("ssdp_listener_start()");
146 
147  /* The structure contining all the filters information */
148  filters_factory_s *filters_factory = NULL;
149 
150  /* Parse the filters */
151  PRINT_DEBUG("parse_filters()");
152  parse_filters(conf->filter, &filters_factory, TRUE & (~conf->quiet_mode));
153 
154  /* Child process server loop */
155  PRINT_DEBUG("Strating infinite loop");
156  ssdp_message_s *ssdp_message;
157  BOOL drop_message;
158 
159  /* Create a list for keeping/caching SSDP messages */
160  ssdp_cache_s *ssdp_cache = NULL;
161 
162  while (!listener->stop) {
163  ssdp_recv_node_s recv_node;
164  drop_message = FALSE;
165  ssdp_message = NULL;
166 
167  PRINT_DEBUG("loop: ready to receive");
168  ssdp_listener_read(listener, &recv_node);
169 
170  #ifdef __DEBUG
171  if (recv_node.recv_bytes > 0) {
172  PRINT_DEBUG("**** RECEIVED %d bytes ****\n%s", recv_node.recv_bytes,
173  notif_string);
174  PRINT_DEBUG("************************");
175  }
176  #endif
177 
178  /* If timeout reached then go through the
179  ssdp_cache list and see if anything needs
180  to be sent */
181  if (recv_node.recv_bytes < 1) {
182  PRINT_DEBUG("Timed-out waiting for a SSDP message");
183  if(!ssdp_cache || *ssdp_cache->ssdp_messages_count == 0) {
184  PRINT_DEBUG("No messages in the SSDP cache, continuing to listen");
185  }
186  else {
187  /* If forwarding has been enabled, send the cached
188  SSDP messages and empty the list*/
189  if(conf->forward_address) {
190  PRINT_DEBUG("Forwarding cached SSDP messages");
191  if(!flush_ssdp_cache(conf, &ssdp_cache, "/abused/post.php",
192  &listener->forwarder, 80, 1)) {
193  PRINT_DEBUG("Failed flushing SSDP cache");
194  continue;
195  }
196  }
197  /* Else just display the cached messages in a table */
198  else {
199  PRINT_DEBUG("Displaying cached SSDP messages");
200  display_ssdp_cache(ssdp_cache, FALSE);
201  }
202  }
203  continue;
204  }
205  /* Else a new ssdp message has been received */
206  else {
207 
208  /* init ssdp_message */
209  if (!init_ssdp_message(&ssdp_message)) {
210  PRINT_ERROR("Failed to initialize the SSDP message buffer");
211  continue;
212  }
213 
214  /* Build the ssdp message struct */
215  if (!build_ssdp_message(ssdp_message, recv_node.from_ip,
216  recv_node.from_mac, recv_node.recv_bytes, recv_node.recv_data)) {
217  PRINT_ERROR("Failed to build the SSDP message");
218  free_ssdp_message(&ssdp_message);
219  continue;
220  }
221 
222  // TODO: Make it recognize both AND and OR (search for ; inside a ,)!!!
223 
224  /* If -M is not set check if it is a M-SEARCH message
225  and drop it */
226  if (conf->ignore_search_msgs && (strstr(ssdp_message->request,
227  "M-SEARCH") != NULL)) {
228  PRINT_DEBUG("Message contains a M-SEARCH request, dropping "
229  "message");
230  free_ssdp_message(&ssdp_message);
231  continue;
232  }
233 
234  /* Check if notification should be used (if any filters have been set) */
235  if (filters_factory != NULL) {
236  drop_message = filter(ssdp_message, filters_factory);
237  }
238 
239  /* If message is not filtered then use it */
240  if (filters_factory == NULL || !drop_message) {
241 
242  /* Add ssdp_message to ssdp_cache
243  (this internally checks for duplicates) */
244  if (!add_ssdp_message_to_cache(&ssdp_cache, &ssdp_message)) {
245  PRINT_ERROR("Failed adding SSDP message to SSDP cache, skipping");
246  continue;
247  }
248 
249  /* Fetch custom fields */
250  if (conf->fetch_info && !fetch_custom_fields(conf, ssdp_message)) {
251  PRINT_DEBUG("Could not fetch custom fields");
252  }
253  ssdp_message = NULL;
254 
255  /* Check if forwarding ('-a') is enabled */
256  if (conf->forward_address) {
257 
258  /* If max ssdp cache size reached then it is time to flush */
259  if (*ssdp_cache->ssdp_messages_count >= conf->ssdp_cache_size) {
260  PRINT_DEBUG("Cache max size reached, sending and emptying");
261  if(!flush_ssdp_cache(conf, &ssdp_cache, "/abused/post.php",
262  &listener->forwarder, 80, 1)) {
263  PRINT_DEBUG("Failed flushing SSDP cache");
264  continue;
265  }
266  }
267  else {
268  PRINT_DEBUG("Cache max size not reached, not sending yet");
269  }
270  }
271  else {
272  /* Display results on console */
273  PRINT_DEBUG("Displaying cached SSDP messages");
274  display_ssdp_cache(ssdp_cache, FALSE);
275  }
276  }
277  }
278 
279  PRINT_DEBUG("scan loop: done");
280  }
281  free_ssdp_filters_factory(filters_factory);
282 
283 
284  return 0;
285 }
286 
288  listener->stop = TRUE;
289 }
SOCKET setup_socket(socket_conf_s *conf)
char ip[IPv6_STR_MAX_SIZE]
Definition: configuration.h:18
BOOL filter(ssdp_message_s *ssdp_message, filters_factory_s *filters_factory)
Definition: ssdp_filter.c:115
int parse_address(const char *raw_address, struct sockaddr_storage *address)
Definition: net_utils.c:33
int SOCKET
char interface[IPv6_STR_MAX_SIZE]
Definition: configuration.h:16
int 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 display_ssdp_cache(ssdp_cache_s *ssdp_cache, BOOL draw_asci)
char * get_mac_address_from_socket(const SOCKET sock, const struct sockaddr_storage *sa_ip, const char *ip, char *mac_buffer)
Definition: net_utils.c:455
void free_ssdp_message(ssdp_message_s **message_pointer)
Definition: ssdp_message.c:608
int fetch_custom_fields(configuration_s *conf, ssdp_message_s *ssdp_message)
Definition: ssdp_message.c:157
void ssdp_listener_close(ssdp_listener_s *listener)
BOOL build_ssdp_message(ssdp_message_s *message, char *ip, char *mac, int message_length, const char *raw_message)
Definition: ssdp_message.c:498
int ssdp_listener_start(ssdp_listener_s *listener, configuration_s *conf)
#define TRUE
#define FALSE
void ssdp_listener_stop(ssdp_listener_s *listener)
char from_ip[IPv6_STR_MAX_SIZE]
Definition: ssdp_common.h:20
#define SSDP_ACTIVE_LISTENER_TIMEOUT
Definition: ssdp_listener.c:39
#define SSDP_PASSIVE_LISTENER_TIMEOUT
Definition: ssdp_listener.c:34
struct sockaddr_storage forwarder
Definition: ssdp_listener.h:20
char from_mac[MAC_STR_MAX_SIZE]
Definition: ssdp_common.h:22
void ssdp_listener_read(ssdp_listener_s *listener, ssdp_recv_node_s *recv_node)
unsigned char ttl
Definition: configuration.h:50
BOOL init_ssdp_message(ssdp_message_s **message_pointer)
Definition: ssdp_message.c:431
char recv_data[SSDP_RECV_DATA_LEN]
Definition: ssdp_common.h:26
BOOL add_ssdp_message_to_cache(ssdp_cache_s **ssdp_cache_pointer, ssdp_message_s **ssdp_message_pointer)
Definition: ssdp_cache.c:290
static int ssdp_listener_init(ssdp_listener_s *listener, configuration_s *conf, BOOL is_active, int port, int recv_timeout)
Definition: ssdp_listener.c:54
void free_ssdp_filters_factory(filters_factory_s *factory)
Definition: ssdp_filter.c:16
#define LISTEN_QUEUE_LENGTH
Definition: ssdp_listener.c:29
int BOOL
#define SSDP_ADDR
static configuration_s conf
Definition: main.c:73
#define SOCKET_ERROR
#define SSDP_PORT
#define SSDP_RECV_DATA_LEN
Definition: ssdp_common.h:15
int ssdp_active_listener_init(ssdp_listener_s *listener, configuration_s *conf, int port)
unsigned int * ssdp_messages_count
Definition: ssdp_cache.h:29
char * get_ip_from_sock_address(const struct sockaddr_storage *saddr, char *ip_buffer)
Definition: net_utils.c:621
int ssdp_passive_listener_init(ssdp_listener_s *listener, configuration_s *conf)
void parse_filters(char *raw_filter, filters_factory_s **filters_factory, BOOL print_filters)
Definition: ssdp_filter.c:38