Comments (21)
Alright, so the current implementation is as follows.
All UDP/RTP sockets are opened the same way. They're opened as an AF_INET6 socket, bound to IN6ADDR_ANY and the respective UDP port (function get_port6()). IPv4 is handled through IPv4-in-IPv6 mapped addresses.
There used to be a function get_port4(), which would open an AF_INET socket when no IPv6 support was available. But support for non-IPv6 enabled hosts was abandoned and thus this function was dropped. Now all sockets are AF_INET6 sockets, always.
The source address of outgoing packets is selected in callmaster_msg_mh_src() (through sendmsg() extensions) and is done solely based on the address family of the destination address. If the destination is an IPv4-in-IPv6 mapped address, then the local IPv4 address (also mapped into IPv6) is chosen, otherwise the IPv6 address is chosen.
This enables rtpengine to freely bridge between IPv4 and IPv6. It doesn't care what kind of address family the incoming packet used, as addresses are always mapped into IPv6 anyway. It only needs to know which source address to use for outgoing packets, IPv4 or IPv6.
As for signalling, the local address advertised to the remote SIP endpoint is determined in call_stream_address(). If the "desired family" for a particular endpoint is known, then this local address (family) is chosen, otherwise the address (family) is determined from the address family of the destination address, if known, same as when sending a UDP/RTP packet.
The "desired family" flag in turn is derived either explicitly from the respective flag within the NG protocol ("address family", see call_ng_process_flags()), or implicitly from the legacy internal/external "direction" flags. The latter method will be obsoleted at some point, but for now must remain intact as it's still being used. The logic for this can be found in monologue_offer_answer().
So to implement same-family bridging, you can either re-use the existing "direction" flags, or introduce a new flag into the NG protocol akin to the "desired family" option to select from multiple local addresses. If you go for the former option, then you'll need a case distinction between IPv4/IPv6 and IPv4/IPv4 bridging. With the latter option, it should be possible to handle multiple addresses and multiple address families simultaneously. You'll also need a way to tell rtpengine about the different addresses that it can use (more CLI arguments?)
from rtpengine.
Thanks for the detailed explanation. Glad, we're having this conversation. Two key points that you've mentioned -
"But support for non-IPv6 enabled hosts was abandoned and thus this function was dropped. Now all sockets are AF_INET6 sockets, always."
"The "desired family" flag in turn is derived either explicitly from the respective flag within the NG protocol ("address family", see call_ng_process_flags()), or implicitly from the legacy internal/external "direction" flags. The latter method will be obsoleted at some point, but for now must remain intact as it's still being used."
I don't have that luxury. I need to support IPv4 only hosts (no dual-stack). So, I need something like get_port4() definitely. So, can I make following assumptions/modifications:
(a) '-i' argument accepts IPv4 only address and it's logically associated with internal (private) interface of the machine.
(b) '-I' accepts IPv4/v6 address (parsing and storing it will be taken care) and will be associated with external (public) interface of the machine.
(c) Introduce 2 new functions (which replace get_port6() function) -
get_internal_port() - opens a AF_INET socket and binds to a port on a Internal IP (v4) interface (provided thru '-i')
get_external_port() - opens a AF_INET or AF_INET6 (based on type of IP provided in '-I' argument) socket and binds to a port on a external IP (v4/v6) interface.
(d) Introduce a new CLI argument, say -d/--mode. Possible values would be
1. bridge - default operational mode. In this mode, it would work in current way.
2. nat - new mode, where packets would be forwarded from internal to external IP and vice versa providing nat traversal based on ng-call-control directives (to be tested with Kamailio).
(e) The legacy internal/external "direction" flag can't be obsoleted as that would be key in 'nat' mode of operation. Is that acceptable?
Thanks,
Dipak
from rtpengine.
Just to clarify: with "no IPv6 support" I meant that AF_INET6 sockets are unsupported by the system. Whether or not the system actually has IPv6 connectivity isn't relevant. Hosts without IPv6 stacks are pretty rare these days, are you sure you require this?
from rtpengine.
Yeah, I know. But, I'm targeting for a tricked out (or rather I would say, down) linux machine where IPv6 is compiled out. So, sock call with AF_INET6 is going to fail regardless. I understand that with IPv6 mapped IPv4, life would have been easier.
from rtpengine.
I see, in that case perhaps a compile-time switch (no-ipv6) would be a good solution, where it always gets an AF_INET socket.
You mention binding to a particular address. Is this required? Right now, IN(6)ADDR_ANY is used, with the source address selected each time a packet is sent. It would be easier to keep this logic in place.
As for "direction" being obsoleted, I meant obsoleted as mechanism for selecting the address family. The flags themselves will stick around.
Perhaps the proposed --mode option isn't even necessary. If both addresses -i and -I are IPv4, then there's only one thing it can do anyway.
from rtpengine.
"The source address of outgoing packets is selected in callmaster_msg_mh_src() (through sendmsg() extensions) and is done solely based on the address family of the destination address. If the destination is an IPv4-in-IPv6 mapped address, then the local IPv4 address (also mapped into IPv6) is chosen, otherwise the IPv6 address is chosen."
I think my use case is different. Though, my destination address is never going to be IPv6, but I've to choose which of the IPv4 I'm going to use as my source address. One option would be to look for source and destination would always be the other IPv4. I thought that would need a (--mode like) option to make that decision, as opposed to current way of making the decision of choosing source family based on destination family.
Can we have a call to discuss and then I can write up the final outline of the decided approach after you agree?
Thanks,
Dipak
from rtpengine.
What I meant was that, if I understand correctly, I think the "mode" can be implicitly inferred from the type of address given to the -I option. If it's IPv6, then everything works as it does now, but if it's IPv4, then not the address family is used as criterion for which source address to choose, but something else (i.e. the "direction" given).
In fact, I think this can be generalized to both -i and -I accepting addresses of either address family. If they're the same address family, then internal/external is used as decision criterion, otherwise the destination address family is used. In the future, this could then be extended to more than 2 local addresses of arbitrary families being supported.
Anyway, just a suggestion. Either way is fine with me.
from rtpengine.
Got it. I, for a while, forgot that you clarified previously, the direction itself is not obsoleted but use of it to determine address family is obsoleted.
So,
1. I'll use "direction" to determine the source address of an outgoing UDP/RTP when both interfaces are of same family (at this time IPv4/IPv4).
2. Use compilation switch to compile out IPv6 socket always and use IPv4 always, instead.
Do you think, I should rather use runtime decision based on '-I' provided address family?
Thanks,
Dipak
from rtpengine.
mmmm, whatever is easier. Hard to tell right now. Generally I'd prefer to only have a single socket type throughout the code to avoid constant case distinctions, but since those distinctions have to be made anyway, either at compile time or at run time, I'd just make it as painless as possible.
from rtpengine.
Hi,
We are also interested in ipv4 to ipv4 bridging (but our system can do ipv6). Although playing with routing and IP masquerading does the trick in our lab, this kind of solution won't scale very easily for us. The best solution would be to specify explicitly the direction (internal <=> external) in the offer or answer commands.
@dipakb, have you had any success on this topic? Have you implemented something already?
@rfuchs, how could this kind of feature fit in your current architecture?
Cheers,
Camille
from rtpengine.
I'm also surprised this feature is not implemented. Unless I am mistake, there is no way currently to proxy RTP between a public and private IPv4 interface.
from rtpengine.
@camilleoudot it shouldn't be too hard to implement this, all sockets listen on inaddr_any/in6addr_any, so the only requirement is to select a different source address through the msghdr struct in sendmsg() and also communicate this to the kernel module.
from rtpengine.
Ok, i'll start looking at the daemon part first. A second IPv4 address should be specified on the command line, and the offer/answer direction
flag should be used to choose the desired bridging direction, instead of ipv4/ipv6 bridging option, right?
Is stream_packet()
[call.c:553] the only function responsible for packet transmission? I guess the stream->rtp_sink
just has to be initalized with the desired address beforehand.
from rtpengine.
My personal preference would be an arbitrary number of local addresses that you can specify at the command line, something like --ip=default/1.2.3.4 --ip=foobar/2.3.4.5 --ip=blah/3.4.5.6 etc... and then have another key within the NG protocol to select one of them, like local-interface=foobar. This could render the internal/external mechanism obsolete, or it could be retained as an alternative selection mechanism. It also allows for grouping of multiple addresses (even from different address families), for example for multiple ICE candidates. The advertised-address switches should also be considered.
The code selecting the source address on outgoing packets is callmaster_msg_mh_src() and is the only place where this needs to be done. For the kernel module, this happens in kernelize() and for signalling/SDP, it's call_stream_address() -- it should be possible to unify the selection code between those three.
The selected source interface can be stored in either one of call_monologue, call_media or packet_stream, perhaps even in the stream_fd. Locking must be considered for safe packet forwarding, since stream_packet doesn't lock the entire call.
from rtpengine.
It also allows for grouping of multiple addresses (even from different address families)
do you mean we should be able to specify multiple addresses from both families under the same name, like --ip=foo/1.2.3.4 --ip=foo/9.8.7.6 --ip=foo/::1:2:3:4
? Or should we uniquely associate one name to one address?
Also, could you elaborate on grouping for ICE candidates?
from rtpengine.
Well, right now you can have one IPv4 address and one IPv6 address. If both are given and IPv4 is to be used for a particular SIP message, then IPv4 will be used in the c= line. If ICE is also active, then IPv4 will be used as the first ICE candidate, but a second ICE candidate will also be generated with the IPv6 address. And vice versa.
So in this example, the IPv4 address and the IPv6 address form a "group". It would make sense to allow an arbitrary number of address of arbitrary families to be grouped in an arbitrary way. The primary address of each group would be used for c= lines (depending on which family is to be used) and the remaining ones would be used for ICE candidates if ICE is enabled.
So in your example, you'd have 3 addresses in one group named "foo". If IPv4 is desired, 1.2.3.4 would be put into the c= line and ::1:2:3:4 if IPv6 is desired. In either case, all addresses would be used for ICE candidates, but the c= line address always as first candidate (and perhaps all other addresses from the same family as the higher-priority candidates).
This is how I would do it, anyway. Just a suggestion! If you have other/better ideas, then by all means.
from rtpengine.
Just a heads-up that this is in development right and nearing completion. Keep an eye out on the branch rfuchs/interface-bridging
from rtpengine.
Hi Richard,
thanks, this is great news. I started implementing something a couple of weeks ago, but did not finish, so we'll now focus on your branch. I'll test it very soon.
from rtpengine.
I've tested it, and it's working fine. Is there something left to implement?
from rtpengine.
Nope, just some more testing from our side, but I think it's looking pretty good.
from rtpengine.
Merged into master as of d1165df therefore closing
from rtpengine.
Related Issues (20)
- UBSAN: array-index-out-of-bounds in /var/lib/dkms/rtpengine/12.2.1.5/build/xt_RTPENGINE.c:5156:32
- compile rtpengine failed on ubuntu 22.04 with error "undefined reference to `av_channel_layout_default'" HOT 4
- SRTP output wanted, but no crypto suite was negotiated HOT 1
- rtpengine mr10.5 crashed in __dtx_send_later HOT 2
- `silent-timeout` not working HOT 1
- for rhel 8.9 mr11.5 there is an compilation issue HOT 1
- rtpengine not support H264 HOT 1
- call.h:921:7: error: unknown type name ‘__auto_type
- kamailio rtpengine re-INVITE HOT 1
- kzalloc() return 0. HOT 6
- DKMS Rebuild modules failed HOT 2
- libg729 crash on rtpengine 9.5.2
- Wrong IPv session stats HOT 3
- ipv4 only media current sessions number wrong after restart HOT 1
- numsessions "current sessions own" and "ipv4 only media" almost always differ HOT 1
- RTP silent-timeou is not working HOT 3
- no log output HOT 1
- How to get linux/btree.h HOT 2
- SRTP with Kamailio Signalling HOT 1
- 如果在某些云主机上部署出现报错绑定网卡相关的问题,可以尝试使用这个仓库中的两个文件替换,属于魔改版
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rtpengine.