Browse code

support for forcing outbound network interface on packets sent (RTP/SIP)

Raphael Coeffic authored on 13/11/2012 13:01:13
Showing 10 changed files
... ...
@@ -83,6 +83,7 @@ bool         AmConfig::ForceOutboundProxy      = false;
83 83
 string       AmConfig::NextHop                 = "";
84 84
 bool         AmConfig::NextHop1stReq           = false;
85 85
 bool         AmConfig::ProxyStickyAuth         = false;
86
+bool         AmConfig::ForceOutboundIf         = false;
86 87
 bool         AmConfig::IgnoreNotifyLowerCSeq   = false;
87 88
 bool         AmConfig::DisableDNSSRV           = false;
88 89
 string       AmConfig::Signature               = "";
... ...
@@ -334,6 +335,10 @@ int AmConfig::readConfiguration()
334 335
     ProxyStickyAuth = (cfg.getParameter("proxy_sticky_auth") == "yes");
335 336
   }
336 337
 
338
+  if(cfg.hasParameter("force_outbound_if")) {
339
+    ForceOutboundIf = (cfg.getParameter("force_outbound_if") == "yes");
340
+  }
341
+
337 342
   if(cfg.hasParameter("ignore_notify_lower_cseq")) {
338 343
     IgnoreNotifyLowerCSeq = (cfg.getParameter("ignore_notify_lower_cseq") == "yes");
339 344
   }
... ...
@@ -880,6 +885,45 @@ int AmConfig::finalizeIPConfig()
880 885
 	}
881 886
       }
882 887
     }
888
+
889
+    for(list<SysIntf>::iterator it=SysIfs.begin();
890
+	it != SysIfs.end(); it++) {
891
+
892
+      if(Ifs[i].MediaIf.empty()) {
893
+	list<IPAddr>::iterator addr_it = it->addrs.begin();
894
+	while(addr_it != it->addrs.end()) {
895
+	  if(Ifs[i].LocalIP == addr_it->addr)
896
+	    break;
897
+	}
898
+	if(addr_it != it->addrs.end()) {
899
+	  Ifs[i].MediaIf = it->name;
900
+	  Ifs[i].MediaIfIdx = if_nametoindex(it->name.c_str());
901
+	}
902
+      }
903
+
904
+      if(Ifs[i].SipIf.empty()) {
905
+	list<IPAddr>::iterator addr_it = it->addrs.begin();
906
+	while(addr_it != it->addrs.end()) {
907
+	  if(Ifs[i].LocalSIPIP == addr_it->addr)
908
+	    break;
909
+	}
910
+	if(addr_it != it->addrs.end()) {
911
+	  Ifs[i].SipIf = it->name;
912
+	  Ifs[i].SipIfIdx = if_nametoindex(it->name.c_str());
913
+	}
914
+      }
915
+    }
916
+
917
+    if(Ifs[i].SipIf.empty() || Ifs[i].MediaIf.empty()||
918
+       !Ifs[i].SipIfIdx || !Ifs[i].MediaIfIdx) {
919
+
920
+      ERROR("Could not find coresponding proper network interface for '%s'\n",
921
+	    Ifs[i].name.c_str());
922
+      ERROR("\tSIP interface: '%s'\n", Ifs[i].SipIf.c_str());
923
+      ERROR("\tSIP interface idx: '%i'\n", Ifs[i].SipIfIdx);
924
+      ERROR("\tRTP interface: '%s'\n", Ifs[i].MediaIf.c_str());
925
+      ERROR("\tSIP interface idx: '%i'\n", Ifs[i].MediaIfIdx);
926
+    }
883 927
   }
884 928
 
885 929
   return 0;
... ...
@@ -892,12 +936,12 @@ void AmConfig::dump_Ifs()
892 936
     IP_interface& it_ref = Ifs[i];
893 937
 
894 938
     INFO("Interface: '%s' (%i)",it_ref.name.c_str(),i);
895
-    INFO("\tLocalIP='%s'",it_ref.LocalIP.c_str());
939
+    INFO("\tmedia IP = '%s'/[%u;%u]",it_ref.LocalIP.c_str(),
940
+	 it_ref.RtpLowPort,it_ref.RtpHighPort);
941
+    INFO("\tmedia If = '%s'/%u",it_ref.MediaIf.c_str(),it_ref.MediaIfIdx);
942
+    INFO("\tSIP IP = '%s'/%u",it_ref.LocalSIPIP.c_str(),it_ref.LocalSIPPort);
943
+    INFO("\tSIP If='%s'/%u",it_ref.SipIf.c_str(),it_ref.SipIfIdx);
896 944
     INFO("\tPublicIP='%s'",it_ref.PublicIP.c_str());
897
-    INFO("\tLocalSIPIP='%s'",it_ref.LocalSIPIP.c_str());
898
-    INFO("\tLocalSIPPort=%u",it_ref.LocalSIPPort);
899
-    INFO("\tRtpLowPort=%u",it_ref.RtpLowPort);
900
-    INFO("\tRtpHighPort=%u",it_ref.RtpHighPort);
901 945
   }
902 946
   
903 947
   INFO("Signaling address map:");
... ...
@@ -100,6 +100,14 @@ struct AmConfig
100 100
     /** the port SIP requests are sent from - optional (default 5060) */
101 101
     int LocalSIPPort;
102 102
 
103
+    /** Network interface name and index for media */
104
+    string       MediaIf;
105
+    unsigned int MediaIfIdx;
106
+
107
+    /** Network interface name and index for signaling */
108
+    string       SipIf;
109
+    unsigned int SipIfIdx;
110
+
103 111
     /** options for the signaling socket (@see trsp_socket::socket_options) */
104 112
     unsigned int SigSockOpts;
105 113
 
... ...
@@ -158,6 +166,8 @@ struct AmConfig
158 166
   static bool NextHop1stReq;
159 167
   /** update ruri-host to previously resolved IP:port on SIP auth */
160 168
   static bool ProxyStickyAuth;
169
+  /** force the outbound network interface / short-circuit the routing table */
170
+  static bool ForceOutboundIf;
161 171
   /** Ignore Low CSeq on NOTIFY  - for RFC 3265 instead of 5057 */
162 172
   static bool IgnoreNotifyLowerCSeq;
163 173
   /** skip DNS SRV lookup for resolving destination address*/
... ...
@@ -169,7 +179,7 @@ struct AmConfig
169 179
   /** If 200 OK reply should be limited to preferred codec only */
170 180
   static bool SingleCodecInOK;
171 181
   static vector <string> CodecOrder;
172
-  
182
+
173 183
   enum ApplicationSelector {
174 184
     App_RURIUSER,
175 185
     App_RURIPARAM,
... ...
@@ -25,6 +25,9 @@
25 25
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 26
  */
27 27
 
28
+#define __APPLE_USE_RFC_3542
29
+#include <netinet/in.h>
30
+
28 31
 #include "AmRtpPacket.h"
29 32
 #include "rtp/rtp.h"
30 33
 #include "log.h"
... ...
@@ -37,7 +40,6 @@
37 40
 #include <errno.h>
38 41
 
39 42
 #include <sys/socket.h>
40
-#include <netinet/in.h>
41 43
 #include <arpa/inet.h>
42 44
 
43 45
 AmRtpPacket::AmRtpPacket()
... ...
@@ -180,11 +182,11 @@ int AmRtpPacket::compile_raw(unsigned char* data_buf, unsigned int size)
180 182
   return size;
181 183
 }
182 184
 
183
-int AmRtpPacket::send(int sd)
185
+int AmRtpPacket::sendto(int sd)
184 186
 {
185
-  int err = sendto(sd,buffer,b_size,0,
186
-		   (const struct sockaddr *)&addr,
187
-		   SA_len(&addr));
187
+  int err = ::sendto(sd,buffer,b_size,0,
188
+		     (const struct sockaddr *)&addr,
189
+		     SA_len(&addr));
188 190
 
189 191
   if(err == -1){
190 192
     ERROR("while sending RTP packet: %s\n",strerror(errno));
... ...
@@ -194,6 +196,68 @@ int AmRtpPacket::send(int sd)
194 196
   return 0;
195 197
 }
196 198
 
199
+int AmRtpPacket::sendmsg(int sd, unsigned int sys_if_idx)
200
+{
201
+  struct msghdr hdr;
202
+  struct cmsghdr* cmsg;
203
+    
204
+  union {
205
+    char cmsg4_buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
206
+    char cmsg6_buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
207
+  } cmsg_buf;
208
+
209
+  struct iovec msg_iov[1];
210
+  msg_iov[0].iov_base = (void*)buffer;
211
+  msg_iov[0].iov_len  = b_size;
212
+
213
+  bzero(&hdr,sizeof(hdr));
214
+  hdr.msg_name = (void*)&addr;
215
+  hdr.msg_namelen = SA_len(&addr);
216
+  hdr.msg_iov = msg_iov;
217
+  hdr.msg_iovlen = 1;
218
+
219
+  bzero(&cmsg_buf,sizeof(cmsg_buf));
220
+  hdr.msg_control = &cmsg_buf;
221
+  hdr.msg_controllen = sizeof(cmsg_buf);
222
+
223
+  cmsg = CMSG_FIRSTHDR(&hdr);
224
+  if(addr.ss_family == AF_INET) {
225
+    cmsg->cmsg_level = IPPROTO_IP;
226
+    cmsg->cmsg_type = IP_PKTINFO;
227
+    cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
228
+
229
+    struct in_pktinfo* pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
230
+    pktinfo->ipi_ifindex = sys_if_idx;
231
+  }
232
+  else if(addr.ss_family == AF_INET6) {
233
+    cmsg->cmsg_level = IPPROTO_IPV6;
234
+    cmsg->cmsg_type = IPV6_PKTINFO;
235
+    cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
236
+    
237
+    struct in6_pktinfo* pktinfo = (struct in6_pktinfo*) CMSG_DATA(cmsg);
238
+    pktinfo->ipi6_ifindex = sys_if_idx;
239
+  }
240
+
241
+  hdr.msg_controllen = cmsg->cmsg_len;
242
+  
243
+  // bytes_sent = ;
244
+  if(::sendmsg(sd, &hdr, 0) < 0) {
245
+      ERROR("sendto: %s\n",strerror(errno));
246
+      return -1;
247
+  }
248
+
249
+  return 0;
250
+}
251
+
252
+int AmRtpPacket::send(int sd, unsigned int sys_if_idx)
253
+{
254
+  if(sys_if_idx && AmConfig::ForceOutboundIf) {
255
+    return sendmsg(sd,sys_if_idx);
256
+  }
257
+  
258
+  return sendto(sd);
259
+}
260
+
197 261
 int AmRtpPacket::recv(int sd)
198 262
 {
199 263
   socklen_t recv_addr_len = sizeof(struct sockaddr_storage);
... ...
@@ -43,6 +43,9 @@ class AmRtpPacket {
43 43
   unsigned int   data_offset;
44 44
   unsigned int   d_size;
45 45
 
46
+  int sendto(int sd);
47
+  int sendmsg(int sd, unsigned int sys_if_idx);
48
+
46 49
 public:
47 50
   unsigned char  payload;
48 51
   bool           marker;
... ...
@@ -64,7 +67,7 @@ public:
64 67
   // returns -1 if error, else 0
65 68
   int compile_raw(unsigned char* data_buf, unsigned int size);
66 69
 
67
-  int send(int sd);
70
+  int send(int sd, unsigned int sys_if_idx=0);
68 71
   int recv(int sd);
69 72
 
70 73
   int parse();
... ...
@@ -224,7 +224,7 @@ int AmRtpStream::ping()
224 224
   rp.compile((unsigned char*)ping_chr,2);
225 225
 
226 226
   rp.setAddr(&r_saddr);
227
-  if(rp.send(l_sd) < 0){
227
+  if(rp.send(l_sd, AmConfig::Ifs[l_if].MediaIfIdx) < 0){
228 228
     ERROR("while sending RTP packet.\n");
229 229
     return -1;
230 230
   }
... ...
@@ -273,7 +273,7 @@ int AmRtpStream::compile_and_send(const int payload, bool marker, unsigned int t
273 273
   }
274 274
 #endif
275 275
 
276
-  if(rp.send(l_sd) < 0){
276
+  if(rp.send(l_sd, AmConfig::Ifs[l_if].MediaIfIdx) < 0){
277 277
     ERROR("while sending RTP packet.\n");
278 278
     return -1;
279 279
   }
... ...
@@ -310,7 +310,7 @@ int AmRtpStream::send_raw( char* packet, unsigned int length )
310 310
   rp.compile_raw((unsigned char*)packet, length);
311 311
   rp.setAddr(&r_saddr);
312 312
 
313
-  if(rp.send(l_sd) < 0){
313
+  if(rp.send(l_sd, AmConfig::Ifs[l_if].MediaIfIdx) < 0){
314 314
     ERROR("while sending raw RTP packet.\n");
315 315
     return -1;
316 316
   }
... ...
@@ -983,7 +983,7 @@ void AmRtpStream::relay(AmRtpPacket* p) {
983 983
     hdr->ssrc = htonl(l_ssrc);
984 984
   p->setAddr(&r_saddr);
985 985
 
986
-  if(p->send(l_sd) < 0){
986
+  if(p->send(l_sd, AmConfig::Ifs[l_if].MediaIfIdx) < 0){
987 987
     ERROR("while sending RTP packet to '%s':%i\n",
988 988
 	  get_addr_str(&r_saddr).c_str(),am_get_port(&r_saddr));
989 989
   }
... ...
@@ -241,7 +241,10 @@ int SipCtrlInterface::run()
241 241
     for(unsigned int i=0; i<AmConfig::Ifs.size();i++) {
242 242
 
243 243
 	udp_trsp_socket* udp_socket = 
244
-	    new udp_trsp_socket(i,AmConfig::Ifs[i].SigSockOpts);
244
+	    new udp_trsp_socket(i,AmConfig::Ifs[i].SigSockOpts
245
+				| (AmConfig::ForceOutboundIf ? 
246
+				   trsp_socket::force_outbound_if : 0),
247
+				AmConfig::Ifs[i].SipIfIdx);
245 248
 
246 249
 	if(udp_socket->bind(AmConfig::Ifs[i].LocalSIPIP,
247 250
 			    AmConfig::Ifs[i].LocalSIPPort) < 0){
... ...
@@ -35,8 +35,11 @@
35 35
 
36 36
 int trsp_socket::log_level_raw_msgs = L_DBG;
37 37
 
38
-trsp_socket::trsp_socket(unsigned short if_num, unsigned int opts)
39
-    : sd(0), ip(), port(0), if_num(if_num), socket_options(opts)
38
+trsp_socket::trsp_socket(unsigned short if_num, unsigned int opts,
39
+			 unsigned int sys_if_idx)
40
+    : sd(0), ip(), port(0), 
41
+      if_num(if_num), sys_if_idx(sys_if_idx),
42
+      socket_options(opts)
40 43
 {
41 44
     memset(&addr,0,sizeof(sockaddr_storage));
42 45
 }
... ...
@@ -102,30 +105,6 @@ unsigned short trsp_socket::get_if()
102 105
     return if_num;
103 106
 }
104 107
 
105
-int trsp_socket::send(const sockaddr_storage* sa, const char* msg, 
106
-		      const int msg_len)
107
-{
108
-    if (log_level_raw_msgs >= 0) {
109
-	_LOG(log_level_raw_msgs, 
110
-	     "send  msg\n--++--\n%.*s--++--\n", msg_len, msg);
111
-    }
112
-
113
-  int err = sendto(sd, msg, msg_len, 0, (const struct sockaddr*)sa, 
114
-		   sa->ss_family == AF_INET ? 
115
-		   sizeof(sockaddr_in) : sizeof(sockaddr_in6));
116
-
117
-  if (err < 0) {
118
-    ERROR("sendto: %s\n",strerror(errno));
119
-    return err;
120
-  }
121
-  else if (err != msg_len) {
122
-    ERROR("sendto: sent %i instead of %i bytes\n", err, msg_len);
123
-    return -1;
124
-  }
125
-
126
-  return 0;
127
-}
128
-
129 108
 transport::~transport()
130 109
 {
131 110
 }
... ...
@@ -39,7 +39,8 @@ class trsp_socket
39 39
 {
40 40
 public:
41 41
     enum socket_options {
42
-	force_via_address = (1 << 0)
42
+	force_via_address = (1 << 0),
43
+	force_outbound_if = (1 << 1)
43 44
     };
44 45
 
45 46
     static int log_level_raw_msgs;
... ...
@@ -57,14 +58,18 @@ protected:
57 58
     // bound port number
58 59
     unsigned short   port;
59 60
 
60
-    // interface number
61
+    // internal interface number
61 62
     unsigned short   if_num;
62 63
 
64
+    // network interface index
65
+    unsigned int sys_if_idx;
66
+
63 67
     // ORed field of socket_option
64 68
     unsigned int socket_options;
65 69
 
66 70
 public:
67
-    trsp_socket(unsigned short if_num, unsigned int opts);
71
+    trsp_socket(unsigned short if_num, unsigned int opts,
72
+		unsigned int sys_if_idx = 0);
68 73
     virtual ~trsp_socket();
69 74
 
70 75
     /**
... ...
@@ -113,7 +118,7 @@ public:
113 118
      * Sends a message.
114 119
      * @return -1 if error(s) occured.
115 120
      */
116
-    virtual int send(const sockaddr_storage* sa, const char* msg, const int msg_len);
121
+    virtual int send(const sockaddr_storage* sa, const char* msg, const int msg_len)=0;
117 122
 };
118 123
 
119 124
 class transport: public AmThread
... ...
@@ -38,10 +38,11 @@
38 38
 
39 39
 #include "SipCtrlInterface.h"
40 40
 
41
-#include <netdb.h>
42
-
43 41
 #include <sys/param.h>
44 42
 #include <arpa/inet.h>
43
+#include <sys/socket.h>
44
+#include <net/if.h>
45
+#include <netdb.h>
45 46
 
46 47
 #include <errno.h>
47 48
 #include <string.h>
... ...
@@ -159,6 +160,98 @@ int udp_trsp_socket::bind(const string& bind_ip, unsigned short bind_port)
159 160
     return 0;
160 161
 }
161 162
 
163
+int udp_trsp_socket::sendto(const sockaddr_storage* sa, 
164
+			    const char* msg, 
165
+			    const int msg_len)
166
+{
167
+  int err = ::sendto(sd, msg, msg_len, 0, 
168
+		     (const struct sockaddr*)sa, 
169
+		     SA_len(sa));
170
+
171
+  if (err < 0) {
172
+    ERROR("sendto: %s\n",strerror(errno));
173
+    return err;
174
+  }
175
+  else if (err != msg_len) {
176
+    ERROR("sendto: sent %i instead of %i bytes\n", err, msg_len);
177
+    return -1;
178
+  }
179
+
180
+  return 0;
181
+}
182
+
183
+int udp_trsp_socket::sendmsg(const sockaddr_storage* sa, 
184
+			     const char* msg, 
185
+			     const int msg_len)
186
+{
187
+    struct msghdr hdr;
188
+    struct cmsghdr* cmsg;
189
+
190
+  union {
191
+    char cmsg4_buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
192
+    char cmsg6_buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
193
+  } cmsg_buf;
194
+
195
+  struct iovec msg_iov[1];
196
+  msg_iov[0].iov_base = (void*)msg;
197
+  msg_iov[0].iov_len  = msg_len;
198
+
199
+  bzero(&hdr,sizeof(hdr));
200
+  hdr.msg_name = (void*)sa;
201
+  hdr.msg_namelen = SA_len(sa);
202
+  hdr.msg_iov = msg_iov;
203
+  hdr.msg_iovlen = 1;
204
+
205
+  bzero(&cmsg_buf,sizeof(cmsg_buf));
206
+  hdr.msg_control = &cmsg_buf;
207
+  hdr.msg_controllen = sizeof(cmsg_buf);
208
+
209
+  cmsg = CMSG_FIRSTHDR(&hdr);
210
+  if(sa->ss_family == AF_INET) {
211
+
212
+    cmsg->cmsg_level = IPPROTO_IP;
213
+    cmsg->cmsg_type = IP_PKTINFO;
214
+    cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
215
+
216
+    struct in_pktinfo* pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
217
+    pktinfo->ipi_ifindex = sys_if_idx;
218
+  }
219
+  else if(sa->ss_family == AF_INET6) {
220
+    cmsg->cmsg_level = IPPROTO_IPV6;
221
+    cmsg->cmsg_type = IPV6_PKTINFO;
222
+    cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
223
+    
224
+    struct in6_pktinfo* pktinfo = (struct in6_pktinfo*) CMSG_DATA(cmsg);
225
+    pktinfo->ipi6_ifindex = sys_if_idx;
226
+  }
227
+
228
+  hdr.msg_controllen = cmsg->cmsg_len;
229
+  
230
+  // bytes_sent = ;
231
+  if(::sendmsg(sd, &hdr, 0) < 0) {
232
+      ERROR("sendto: %s\n",strerror(errno));
233
+      return -1;
234
+  }
235
+
236
+  return 0;
237
+}
238
+
239
+int udp_trsp_socket::send(const sockaddr_storage* sa, 
240
+			  const char* msg, 
241
+			  const int msg_len)
242
+{
243
+    if (log_level_raw_msgs >= 0) {
244
+	_LOG(log_level_raw_msgs, 
245
+	     "send  msg\n--++--\n%.*s--++--\n", msg_len, msg);
246
+    }
247
+
248
+    if(socket_options & force_outbound_if)
249
+	return sendmsg(sa,msg,msg_len);
250
+    
251
+    return sendto(sa,msg,msg_len);
252
+}
253
+
254
+
162 255
 /** @see trsp_socket */
163 256
 
164 257
 udp_trsp::udp_trsp(udp_trsp_socket* sock)
... ...
@@ -44,8 +44,12 @@ using std::string;
44 44
 
45 45
 class udp_trsp_socket: public trsp_socket
46 46
 {
47
+    int sendto(const sockaddr_storage* sa, const char* msg, const int msg_len);
48
+    int sendmsg(const sockaddr_storage* sa, const char* msg, const int msg_len);
49
+
47 50
 public:
48
-    udp_trsp_socket(unsigned short if_num, unsigned int opts) 
51
+    udp_trsp_socket(unsigned short if_num, unsigned int opts,
52
+		    unsigned int sys_if_idx = 0)
49 53
 	: trsp_socket(if_num,opts) {}
50 54
 
51 55
     ~udp_trsp_socket() {}
... ...
@@ -55,6 +59,12 @@ public:
55 59
      * @return -1 if error(s) occured.
56 60
      */
57 61
     virtual int bind(const string& address, unsigned short port);
62
+
63
+    /**
64
+     * Sends a message.
65
+     * @return -1 if error(s) occured.
66
+     */
67
+    int send(const sockaddr_storage* sa, const char* msg, const int msg_len);
58 68
 };
59 69
 
60 70
 class udp_trsp: public transport