Coverage Report

Created: 2026-10-28 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensips/net/proto_udp/proto_udp.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2015 - OpenSIPS Foundation
3
 * Copyright (C) 2001-2003 FhG Fokus
4
 *
5
 * This file is part of opensips, a free SIP server.
6
 *
7
 * opensips is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version
11
 *
12
 * opensips is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
20
 *
21
 *
22
 * History:
23
 * -------
24
 *  2015-02-11  first version (bogdan)
25
 */
26
27
#include <errno.h>
28
#include <unistd.h>
29
#include <netinet/tcp.h>
30
#include <poll.h>
31
#include <fcntl.h>
32
33
#include "../../pt.h"
34
#include "../../timer.h"
35
#include "../../socket_info.h"
36
#include "../../receive.h"
37
#include "../../parser/msg_parser.h"
38
#include "../api_proto.h"
39
#include "../api_proto_net.h"
40
#include "../net_udp.h"
41
#include "../proxy_protocol.h"
42
#include "proto_udp.h"
43
44
45
static int mod_init(void);
46
static int proto_udp_init(struct proto_info *pi);
47
static int proto_udp_init_listener(struct socket_info *si);
48
static int proto_udp_bind_listener(struct socket_info *si);
49
static int proto_udp_send(const struct socket_info* send_sock,
50
    char* buf, unsigned int len, const union sockaddr_union* to,
51
    unsigned int id, struct sip_msg *msg);
52
53
static int udp_read_req(const struct socket_info *src, int* bytes_read);
54
55
static callback_list* cb_list = NULL;
56
57
static int udp_port = SIP_PORT;
58
59
60
static const cmd_export_t cmds[] = {
61
  {"proto_init", (cmd_function)proto_udp_init, {{0,0,0}}, 0},
62
  {0,0,{{0,0,0}},0}
63
};
64
65
66
static const param_export_t params[] = {
67
  { "udp_port",    INT_PARAM,   &udp_port   },
68
  {0, 0, 0}
69
};
70
71
72
struct module_exports proto_udp_exports = {
73
  PROTO_PREFIX "udp",  /* module name*/
74
  MOD_TYPE_DEFAULT,/* class of this module */
75
  MODULE_VERSION,
76
  DEFAULT_DLFLAGS, /* dlopen flags */
77
  0,               /* load function */
78
  NULL,            /* OpenSIPS module dependencies */
79
  cmds,       /* exported functions */
80
  0,          /* exported async functions */
81
  params,     /* module parameters */
82
  0,          /* exported statistics */
83
  0,          /* exported MI functions */
84
  0,          /* exported pseudo-variables */
85
  0,      /* exported transformations */
86
  0,          /* extra processes */
87
  0,          /* module pre-initialization function */
88
  mod_init,   /* module initialization function */
89
  0,          /* response function */
90
  0,          /* destroy function */
91
  0,          /* per-child init function */
92
  0           /* reload confirm function */
93
};
94
95
96
static int mod_init(void)
97
0
{
98
0
  LM_INFO("initializing UDP-plain protocol\n");
99
0
  return 0;
100
0
}
101
102
103
static int proto_udp_init(struct proto_info *pi)
104
0
{
105
0
  pi->id          = PROTO_UDP;
106
0
  pi->name        = "udp";
107
0
  pi->default_port    = udp_port;
108
109
0
  pi->tran.init_listener  = proto_udp_init_listener;
110
0
  pi->tran.bind_listener  = proto_udp_bind_listener;
111
0
  pi->tran.send     = proto_udp_send;
112
113
0
  pi->net.flags     = PROTO_NET_USE_UDP | PROTO_NET_SUPPORTS_PROXY;
114
0
  pi->net.dgram.read    = udp_read_req;
115
116
0
  return 0;
117
0
}
118
119
120
static int proto_udp_init_listener(struct socket_info *si)
121
0
{
122
  /* we do not do anything particular to UDP plain here, so
123
   * transparently use the generic listener init from net UDP layer */
124
0
  return udp_init_listener(si, O_NONBLOCK);
125
0
}
126
127
static int proto_udp_bind_listener(struct socket_info *si)
128
0
{
129
0
  return udp_bind_listener(si);
130
0
}
131
132
static int udp_read_req(const struct socket_info *si, int* bytes_read)
133
0
{
134
0
  struct receive_info ri;
135
0
  int len;
136
0
  static char buf [BUF_SIZE+1];
137
0
  char *tmp;
138
0
  unsigned int fromlen;
139
0
  callback_list* p;
140
0
  str msg;
141
142
0
  fromlen=sockaddru_len(si->su);
143
  /* coverity[overrun-buffer-arg: FALSE] - union has 28 bytes, CID #200029 */
144
0
  len=recvfrom(si->socket, buf, BUF_SIZE,0,&ri.src_su.s,&fromlen);
145
0
  if (len==-1){
146
0
    if (errno==EAGAIN)
147
0
      return 0;
148
0
    if ((errno==EINTR)||(errno==EWOULDBLOCK)|| (errno==ECONNREFUSED))
149
0
      return -1;
150
0
    LM_ERR("recvfrom:[%d] %s\n", errno, strerror(errno));
151
0
    return -2;
152
0
  }
153
154
0
  ri.bind_address = si;
155
0
  ri.dst_port = si->port_no;
156
0
  ri.dst_ip = si->address;
157
0
  ri.proto = si->proto;
158
0
  ri.proto_reserved1 = ri.proto_reserved2 = 0;
159
160
0
  su2ip_addr(&ri.src_ip, &ri.src_su);
161
0
  ri.src_port=su_getport(&ri.src_su);
162
163
0
  msg.s = buf;
164
0
  msg.len = len;
165
166
0
  if (check_udp_proxy_protocol(&msg.s, &msg.len, &ri) < 0)
167
0
    return 0;
168
169
0
  if (msg.len<MIN_UDP_PACKET) {
170
0
    LM_DBG("probing packet received len = %d\n", msg.len);
171
0
    return 0;
172
0
  }
173
174
  /* we must 0-term the messages, receive_msg expects it */
175
0
  msg.s[msg.len]=0; /* no need to save the previous char */
176
177
  /* run callbacks if looks like non-SIP message*/
178
0
  if( !isalpha(msg.s[0]) ){    /* not-SIP related */
179
0
    for(p = cb_list; p; p = p->next){
180
0
      if(p->b == msg.s[1]){
181
0
        if (p->func(bind_address->socket, &ri, &msg, p->param)==0){
182
          /* buffer consumed by callback */
183
0
          break;
184
0
        }
185
0
      }
186
0
    }
187
0
    if (p) return 0;
188
0
  }
189
190
0
  if (ri.src_port==0){
191
0
    tmp=ip_addr2a(&ri.src_ip);
192
0
    LM_INFO("dropping 0 port packet from %s\n", tmp);
193
0
    return 0;
194
0
  }
195
196
  /* receive_msg must free buf too!*/
197
0
  receive_msg( msg.s, msg.len, &ri, NULL, 0);
198
199
0
  return 0;
200
0
}
201
202
203
/**
204
 * Main UDP send function, called from msg_send.
205
 * \see msg_send
206
 * \param source send socket
207
 * \param buf sent data
208
 * \param len data length in bytes
209
 * \param to destination address
210
 * \return -1 on error, the return value from sento on success
211
 */
212
static int proto_udp_send(const struct socket_info* source,
213
    char* buf, unsigned int len, const union sockaddr_union* to,
214
    unsigned int id, struct sip_msg *msg)
215
0
{
216
0
  int n, tolen, pp_len = 0;
217
0
  int dst_port, dbg_len;
218
0
  char pp_hdr[128];
219
0
  struct ip_addr dst_ip;
220
0
  struct msghdr mh;
221
0
  struct iovec iov[2];
222
223
0
  if ((source->flags & SI_PROXY_OUT) != 0) {
224
0
    su2ip_addr(&dst_ip, to);
225
0
    dst_port = su_getport(to);
226
0
    pp_len = build_outbound_proxy_protocol_v1_hdr(msg ? &msg->rcv : NULL,
227
0
        &source->address, source->port_no,
228
0
        &dst_ip, dst_port, pp_hdr, sizeof(pp_hdr));
229
0
    if (pp_len < 0) {
230
0
      LM_ERR("failed to build outbound PROXY header\n");
231
0
      return -1;
232
0
    }
233
0
    dbg_len = pp_len;
234
0
    if (dbg_len >= 2 && pp_hdr[dbg_len - 2] == '\r' &&
235
0
        pp_hdr[dbg_len - 1] == '\n')
236
0
      dbg_len -= 2;
237
0
    LM_DBG("sending outbound PROXY header on UDP %s:%hu -> %s:%d: %.*s\n",
238
0
        ip_addr2a((struct ip_addr *)&source->address), source->port_no,
239
0
        ip_addr2a(&dst_ip), dst_port, dbg_len, pp_hdr);
240
0
  }
241
242
0
  tolen=sockaddru_len(*to);
243
0
again:
244
0
  if (pp_len) {
245
0
    memset(&mh, 0, sizeof(mh));
246
0
    mh.msg_name = (void *)&to->s;
247
0
    mh.msg_namelen = tolen;
248
0
    iov[0].iov_base = pp_hdr;
249
0
    iov[0].iov_len = pp_len;
250
0
    iov[1].iov_base = buf;
251
0
    iov[1].iov_len = len;
252
0
    mh.msg_iov = iov;
253
0
    mh.msg_iovlen = 2;
254
0
    n = sendmsg(source->socket, &mh, 0);
255
0
  } else {
256
0
    n = sendto(source->socket, buf, len, 0, &to->s, tolen);
257
0
  }
258
259
0
  if (n==-1){
260
0
    if (errno==EINTR || errno==EAGAIN) goto again;
261
0
    LM_ERR("sendto(sock,%p,%d,0,%p,%d): %s(%d) [%s:%hu]\n", buf,len,to,
262
0
        tolen,strerror(errno),errno,inet_ntoa(to->sin.sin_addr),
263
0
        ntohs(to->sin.sin_port));
264
0
    if (errno==EINVAL) {
265
0
      LM_CRIT("invalid sendtoparameters\n"
266
0
      "one possible reason is the server is bound to localhost and\n"
267
0
      "attempts to send to the net\n");
268
0
    }
269
0
  }
270
0
  return n;
271
0
}
272
273
274
int register_udprecv_cb(udp_rcv_cb_f* func, void* param, char a, char b)
275
0
{
276
0
  callback_list* new;
277
278
0
  new = (callback_list*) pkg_malloc(sizeof(callback_list));
279
0
  if(!new){
280
0
    LM_ERR("out of pkg memory\n");
281
0
    return -1;
282
0
  }
283
0
  memset(new, 0, sizeof(callback_list));
284
285
0
  new->func = func;
286
0
  new->param = param;
287
0
  new->a = a;
288
0
  new->b = b;
289
0
  new->next = NULL;
290
291
0
  if(!cb_list){
292
0
    cb_list = new;
293
0
  }else{
294
0
    new->next = cb_list;
295
0
    cb_list = new;
296
0
  }
297
298
0
  return 0;
299
0
}