Discussion:
[Kamailio-Users] Accounting: How to avoid a fraudulent BYE with lower CSeq?
Iñaki Baz Castillo
2008-12-18 11:48:33 UTC
Permalink
Hi, first of all I'm sorry for this cross-posting, but I think it
could be interesting for any SIP proxy with accounting capabilities.

I'm thinking in the following flow in which the caller/attacker would
get an unlimited call (but a limited CDR duration):

--------------------------------------------------------------------------
attacker Kamailio (Acc) gateway

INVITE (CSeq 12) ------>
<-------- 407 Proxy Auth

INVITE (CSeq 13) ------>
INVITE (CSeq 13) ------>
<------------------- 200 Ok
<------------------- 200 Ok
<< Acc START >>
ACK (CSeq 13) ----------->
ACK (CSeq 13) ----------->

<******************* RTP ************************>

# Fraudulent BYE !!!
BYE (CSeq 10) ----------->
<< Acc STOP >>
BYE (CSeq 10) ----------->
<-- 500 Req Out of Order
<-- 500 Req Out of Order
--------------------------------------------------------------------------

The call hasn't finished, but Kamailio has ended the accounting for
this call since it received a BYE. And this BYE will generate a
correct ACC Stop action (since it matches From_tag, To_tag and
Call-ID).

I think this is *VERY* dangerous and I hope I'm wrong.

Would help the dialog module here? does the dialog module check the
CSeq of the BYE in some way and could it prevent Kamailio from
generating the ACC STOP action? (I don't think so).

I've also asked in SIP-implementors and an idea could be generating
the ACC STOP action when receiving the 200 OK for the BYE (and not
when receiving the BYE itself). Of course this will be valid when the
gateway is the recipient of the BYE (and we know the gateway is not an
"attacker"), but this is not valid when the recipient of the BYE is an
user since it could send no reply for the BYE.

The only solution I see is:

- Using the dialog module, Kamailio should check the CSeq value in the BYE.
1) Kamailio should forward the BYE just in case the CSeq is higher
than the actual CSeq for this dialog direction.
2) Kamailio should generate the ACC STOP action just in case the CSeq
is higher than the actual CSeq for this dialog direction.

Both 1) and 2) are needed since a gateway could accept a BYE with
wrong CSeq. In this case the call is ended but the accounting STOP
action doesn't exist (infinite call).

But I think this is too complex, isn't it?
--
Iñaki Baz Castillo
<***@aliax.net>
Alex Hermann
2008-12-18 14:14:41 UTC
Permalink
Post by Iñaki Baz Castillo
Hi, first of all I'm sorry for this cross-posting, but I think it
could be interesting for any SIP proxy with accounting capabilities.
But I think this is too complex, isn't it?
It is complex, but not impossible.


I think is is feasable to do accounting on the proxy _IF_ you can trust your
gateways and make use of that trust.

Start accounting on receipt of a 200 OK on an INVITE request.

Stop accounting:
1) On 200 OK (or maybe 481 or other response) from the gateway in response to
a BYE.
2) On BYE from the gateway
--
Greetings,

Alex Hermann
Iñaki Baz Castillo
2008-12-18 14:28:42 UTC
Permalink
Post by Alex Hermann
Post by Iñaki Baz Castillo
Hi, first of all I'm sorry for this cross-posting, but I think it
could be interesting for any SIP proxy with accounting capabilities.
But I think this is too complex, isn't it?
It is complex, but not impossible.
I think is is feasable to do accounting on the proxy _IF_ you can trust your
gateways and make use of that trust.
Start accounting on receipt of a 200 OK on an INVITE request.
1) On 200 OK (or maybe 481 or other response) from the gateway in response to
a BYE.
2) On BYE from the gateway
Is it feasible with the acc module? Can the acc be stoped depending on
the response? is it valid to set the acc flag in on_reply_route?
--
Iñaki Baz Castillo
<***@aliax.net>
Andreas Granig
2008-12-18 14:47:31 UTC
Permalink
Post by Iñaki Baz Castillo
Post by Alex Hermann
1) On 200 OK (or maybe 481 or other response) from the gateway in response to
a BYE.
2) On BYE from the gateway
Is it feasible with the acc module? Can the acc be stoped depending on
the response? is it valid to set the acc flag in on_reply_route?
You could do it manually by checking $T_reply_code and using
acc_db_request() from a failure route.

Andreas
Iñaki Baz Castillo
2008-12-18 14:51:36 UTC
Permalink
Post by Andreas Granig
Post by Iñaki Baz Castillo
Post by Alex Hermann
1) On 200 OK (or maybe 481 or other response) from the gateway in response to
a BYE.
2) On BYE from the gateway
Is it feasible with the acc module? Can the acc be stoped depending on
the response? is it valid to set the acc flag in on_reply_route?
You could do it manually by checking $T_reply_code and using
acc_db_request() from a failure route.
Yes, but it doesn't explain how to do the accounting when receiving
the 200 OK for the BYE.
--
Iñaki Baz Castillo
<***@aliax.net>
Andreas Granig
2008-12-18 14:55:54 UTC
Permalink
Post by Iñaki Baz Castillo
Post by Andreas Granig
Post by Iñaki Baz Castillo
Post by Alex Hermann
1) On 200 OK (or maybe 481 or other response) from the gateway in response to
a BYE.
2) On BYE from the gateway
Is it feasible with the acc module? Can the acc be stoped depending on
the response? is it valid to set the acc flag in on_reply_route?
You could do it manually by checking $T_reply_code and using
acc_db_request() from a failure route.
Yes, but it doesn't explain how to do the accounting when receiving
the 200 OK for the BYE.
Uh, well... register a new failure route and don't set the flag for
automatic accounting when receiving the BYE, and in your failure route,
do something like

if($T_reply_code == 200 || $T_reply_code == 481)
# or whatever you want to account
{
acc_db_request("something", "acc");
}

Or am I missing something?

Andreas
Iñaki Baz Castillo
2008-12-18 15:03:39 UTC
Permalink
Post by Andreas Granig
Post by Iñaki Baz Castillo
Yes, but it doesn't explain how to do the accounting when receiving
the 200 OK for the BYE.
Uh, well... register a new failure route and don't set the flag for
automatic accounting when receiving the BYE, and in your failure route, do
something like
if($T_reply_code == 200 || $T_reply_code == 481)
# or whatever you want to account
{
acc_db_request("something", "acc");
}
Or am I missing something?
Well, failure_route will not be called when receiving a 200 OK in this
BYE transaction.
failure_route is only invoked for [3456]XX responses. 200 can only be
handled in on_reply_route, but I don't know if acc flag can be set in
on_reply_route.
--
Iñaki Baz Castillo
<***@aliax.net>
Andreas Granig
2008-12-18 15:09:09 UTC
Permalink
Post by Iñaki Baz Castillo
Well, failure_route will not be called when receiving a 200 OK in this
BYE transaction.
failure_route is only invoked for [3456]XX responses. 200 can only be
handled in on_reply_route, but I don't know if acc flag can be set in
on_reply_route.
Ah, yeah, you're right :)
I think I was discussing this with Daniel some time ago, and as far as I
remember, he thought it was save to do so (although it's not enabled for
reply route, so you could call a route block from within your reply
route to get around this instead of using failure route, but no
guarantees for that)...

Andreas
Andreas Granig
2008-12-18 15:11:55 UTC
Permalink
Post by Andreas Granig
I think I was discussing this with Daniel some time ago, and as far as I
remember, he thought it was save to do so (although it's not enabled for
Save to call acc_db_request() is what I mean here...
Iñaki Baz Castillo
2008-12-18 15:16:15 UTC
Permalink
Post by Andreas Granig
Post by Andreas Granig
I think I was discussing this with Daniel some time ago, and as far as I
remember, he thought it was save to do so (although it's not enabled for
Save to call acc_db_request() is what I mean here...
Ah, ok, it makes sense. I will try it.

Thanks.
--
Iñaki Baz Castillo
<***@aliax.net>
Daniel-Constantin Mierla
2008-12-18 19:34:22 UTC
Permalink
Hello,
Post by Andreas Granig
Post by Iñaki Baz Castillo
Well, failure_route will not be called when receiving a 200 OK in this
BYE transaction.
failure_route is only invoked for [3456]XX responses. 200 can only be
handled in on_reply_route, but I don't know if acc flag can be set in
on_reply_route.
Ah, yeah, you're right :)
I think I was discussing this with Daniel some time ago, and as far as I
remember,
AFAIK, we discussed about what happens if BYE comes in, proxy is
restarted and then 200OK. BYE transaction was not accounted. So I
suggested the usage of the acc_db_request(). A failed transaction (e.g.,
BYE with a negative reply) can be accounted.

But this one is a case that cannot be solved by using different flags
from acc module. For INVITE, using the t_check_trans() for reply in
onreply_route with latest kamailio version gives the possibility to drop
the reply if there is no ongoing transaction, therefore you can force
the call to fail.

For BYE is different, as you can lost the STOP event, while the call was
established.
Post by Andreas Granig
he thought it was save to do so (although it's not enabled for
reply route, so you could call a route block from within your reply
route to get around this instead of using failure route, but no
guarantees for that)...
The problem with this approach is that acc_*_request() is looking at
first line to get the method type. However, this can be extended to take
it from CSeq if it is reply not request.

Cheers,
Daniel
--
Daniel-Constantin Mierla
http://www.asipto.com
Daniel-Constantin Mierla
2008-12-18 19:43:03 UTC
Permalink
Hello,
Post by Iñaki Baz Castillo
Hi, first of all I'm sorry for this cross-posting, but I think it
could be interesting for any SIP proxy with accounting capabilities.
I'm thinking in the following flow in which the caller/attacker would
--------------------------------------------------------------------------
attacker Kamailio (Acc) gateway
INVITE (CSeq 12) ------>
<-------- 407 Proxy Auth
INVITE (CSeq 13) ------>
INVITE (CSeq 13) ------>
<------------------- 200 Ok
<------------------- 200 Ok
<< Acc START >>
ACK (CSeq 13) ----------->
ACK (CSeq 13) ----------->
<******************* RTP ************************>
# Fraudulent BYE !!!
BYE (CSeq 10) ----------->
<< Acc STOP >>
BYE (CSeq 10) ----------->
<-- 500 Req Out of Order
<-- 500 Req Out of Order
--------------------------------------------------------------------------
The call hasn't finished, but Kamailio has ended the accounting for
this call since it received a BYE. And this BYE will generate a
correct ACC Stop action (since it matches From_tag, To_tag and
Call-ID).
If you use the flags, the BYE will be accounted only if it gets a 200OK.
If you set the failed transaction flag, then BYEs with negative replies
are accounted as well.

However, this does not stop kamailio to account another BYE, which may
have 200ok or other reply code. It is the job of your billing
application to select the right BYE for computing the call duration.
Post by Iñaki Baz Castillo
I think this is *VERY* dangerous and I hope I'm wrong.
You can set accounting for each request withing a dialog (e.g.,
re-INVITE), and you can get many times same type of event (as it is
based on method type). So keep accounting all BYEs you get in your proxy
and chose the latest that match the dialog.

I see a potential issue with NAT traversal, if the session is ended upon
receiving of a BYE, then no audio will go on even the BYE is negatively
answered, which might be good as it forces end of call by parties
(therefore a correct BYE).

Cheers,
Daniel
Post by Iñaki Baz Castillo
Would help the dialog module here? does the dialog module check the
CSeq of the BYE in some way and could it prevent Kamailio from
generating the ACC STOP action? (I don't think so).
I've also asked in SIP-implementors and an idea could be generating
the ACC STOP action when receiving the 200 OK for the BYE (and not
when receiving the BYE itself). Of course this will be valid when the
gateway is the recipient of the BYE (and we know the gateway is not an
"attacker"), but this is not valid when the recipient of the BYE is an
user since it could send no reply for the BYE.
- Using the dialog module, Kamailio should check the CSeq value in the BYE.
1) Kamailio should forward the BYE just in case the CSeq is higher
than the actual CSeq for this dialog direction.
2) Kamailio should generate the ACC STOP action just in case the CSeq
is higher than the actual CSeq for this dialog direction.
Both 1) and 2) are needed since a gateway could accept a BYE with
wrong CSeq. In this case the call is ended but the accounting STOP
action doesn't exist (infinite call).
But I think this is too complex, isn't it?
--
Daniel-Constantin Mierla
http://www.asipto.com
Iñaki Baz Castillo
2008-12-18 20:36:04 UTC
Permalink
Post by Daniel-Constantin Mierla
Post by Iñaki Baz Castillo
The call hasn't finished, but Kamailio has ended the accounting for
this call since it received a BYE. And this BYE will generate a
correct ACC Stop action (since it matches From_tag, To_tag and
Call-ID).
 
If you use the flags, the BYE will be accounted only if it gets a 200OK.
If you set the failed transaction flag, then BYEs with negative replies
are accounted as well.
Ok, I just imagine failed transaction flag for INVITE requests, but clearly
it's also util for BYE accouting :)
Post by Daniel-Constantin Mierla
However, this does not stop kamailio to account another BYE, which may
have 200ok or other reply code. It is the job of your billing
application to select the right BYE for computing the call duration.
Yeah. With radius it should be easy, since the SQL query for SOP action will
ensure that it wasn't a previous matching BYE.



Thanks a lot.
--
Iñaki Baz Castillo
Daniel-Constantin Mierla
2008-12-20 09:25:10 UTC
Permalink
Post by Iñaki Baz Castillo
Post by Daniel-Constantin Mierla
Post by Iñaki Baz Castillo
The call hasn't finished, but Kamailio has ended the accounting for
this call since it received a BYE. And this BYE will generate a
correct ACC Stop action (since it matches From_tag, To_tag and
Call-ID).
If you use the flags, the BYE will be accounted only if it gets a 200OK.
If you set the failed transaction flag, then BYEs with negative replies
are accounted as well.
Ok, I just imagine failed transaction flag for INVITE requests, but clearly
it's also util for BYE accouting :)
Post by Daniel-Constantin Mierla
However, this does not stop kamailio to account another BYE, which may
have 200ok or other reply code. It is the job of your billing
application to select the right BYE for computing the call duration.
Yeah. With radius it should be easy, since the SQL query for SOP action will
ensure that it wasn't a previous matching BYE.
I don't really get it ... would it select the first or last BYE for a
call? Will it accept many BYEs for same call or will trigger failure?

Cheers,
Daniel
--
Daniel-Constantin Mierla
http://www.asipto.com
Iñaki Baz Castillo
2008-12-20 09:55:58 UTC
Permalink
Post by Daniel-Constantin Mierla
Post by Iñaki Baz Castillo
Yeah. With radius it should be easy, since the SQL query for SOP action
will ensure that it wasn't a previous matching BYE.
 
I don't really get it ... would it select the first or last BYE for a
call? Will it accept many BYEs for same call or will trigger failure?
You can configure the SQL "UPDATE" query for the accounting STOP action in
radius, so for example:
- The first matching BYE will fill a row field "completed" and set it to "1".
- At the same time the SQL query has a "WHERE completed = 0".

In this way, just the first BYE will trigger an UPDATE SQL query. Any other
BYE will be discarded by MySQL server because doesn't honor the "WHERE"
clausule and will no "re-update" the accounting row.
--
Iñaki Baz Castillo
Daniel-Constantin Mierla
2008-12-20 10:26:34 UTC
Permalink
Post by Iñaki Baz Castillo
Post by Daniel-Constantin Mierla
Post by Iñaki Baz Castillo
Yeah. With radius it should be easy, since the SQL query for SOP action
will ensure that it wasn't a previous matching BYE.
I don't really get it ... would it select the first or last BYE for a
call? Will it accept many BYEs for same call or will trigger failure?
You can configure the SQL "UPDATE" query for the accounting STOP action in
- The first matching BYE will fill a row field "completed" and set it to "1".
- At the same time the SQL query has a "WHERE completed = 0".
In this way, just the first BYE will trigger an UPDATE SQL query. Any other
BYE will be discarded by MySQL server because doesn't honor the "WHERE"
clausule and will no "re-update" the accounting row.
But, in this case, the last one should be the right one.

Cheers,
Daniel
--
Daniel-Constantin Mierla
http://www.asipto.com
Iñaki Baz Castillo
2008-12-20 11:25:11 UTC
Permalink
Post by Daniel-Constantin Mierla
Post by Iñaki Baz Castillo
Post by Daniel-Constantin Mierla
Post by Iñaki Baz Castillo
Yeah. With radius it should be easy, since the SQL query for SOP action
will ensure that it wasn't a previous matching BYE.
I don't really get it ... would it select the first or last BYE for a
call? Will it accept many BYEs for same call or will trigger failure?
You can configure the SQL "UPDATE" query for the accounting STOP action
- The first matching BYE will fill a row field "completed" and set it to
"1". - At the same time the SQL query has a "WHERE completed = 0".
In this way, just the first BYE will trigger an UPDATE SQL query. Any
other BYE will be discarded by MySQL server because doesn't honor the
"WHERE" clausule and will no "re-update" the accounting row.
But, in this case, the last one should be the right one.
Well, not sure of which case exactly you mean now. I think that the accounting
proxy should ensure that a fraudulent BYE can't not be the first one in
triggering the STOP action.
--
Iñaki Baz Castillo
Daniel-Constantin Mierla
2008-12-21 08:17:07 UTC
Permalink
Post by Iñaki Baz Castillo
Post by Daniel-Constantin Mierla
Post by Iñaki Baz Castillo
Post by Daniel-Constantin Mierla
Post by Iñaki Baz Castillo
Yeah. With radius it should be easy, since the SQL query for SOP action
will ensure that it wasn't a previous matching BYE.
I don't really get it ... would it select the first or last BYE for a
call? Will it accept many BYEs for same call or will trigger failure?
You can configure the SQL "UPDATE" query for the accounting STOP action
- The first matching BYE will fill a row field "completed" and set it to
"1". - At the same time the SQL query has a "WHERE completed = 0".
In this way, just the first BYE will trigger an UPDATE SQL query. Any
other BYE will be discarded by MySQL server because doesn't honor the
"WHERE" clausule and will no "re-update" the accounting row.
But, in this case, the last one should be the right one.
Well, not sure of which case exactly you mean now. I think that the accounting
proxy should ensure that a fraudulent BYE can't not be the first one in
triggering the STOP action.
I see the proxy just as a reporting point, sending to accounting system
all events within a session:
- START (200ok for INVITE, confirmed - ACK)
- UPDATEs (re-INVITE, other in-session requests)
- STOP (good, bad BYEs)

Then it comes the billing application that implements the logic to deal
with different cases. Easiest one is when you have one STOP event, but
if you have more, then you have to check for reply code, cseq, etc...

The proxy is critical because of the real-time nature of the
communication. Billing can sit and digest peacefully, report abnormally
cases, etc. Many tend to load the proxy with functionalities that don't
belong there, then start complaining is not doing the job right or fast
enough ... in every system you have to get to a compromise, not only in
VoIP.

Cheers,
Daniel
--
Daniel-Constantin Mierla
http://www.asipto.com
Iñaki Baz Castillo
2008-12-21 13:50:07 UTC
Permalink
Post by Daniel-Constantin Mierla
Then it comes the billing application that implements the logic to deal
with different cases. Easiest one is when you have one STOP event, but
if you have more, then you have to check for reply code, cseq, etc...
Well, as I said I don't need dealing with it if I use radius ACC since only
one BYE matching the dialog can trigger a SQL STOP action (other BYE's
matching this dialog will trigger radius STOP action, but not SQL action due
to "WHERE" clausules the SQL query).

So the only I need is the proxy ensures that the BYE is not fraudulent, for
example, it's not a spoofed BYE from the user with RURI=same_user.

Anyway, it seems really complex and a post-accounting process should be needed
as you say. I will try to avoid needing it doing the billing in a B2BUA.

Tahnks.
--
Iñaki Baz Castillo
Daniel-Constantin Mierla
2008-12-22 14:10:33 UTC
Permalink
Post by Iñaki Baz Castillo
Post by Daniel-Constantin Mierla
Then it comes the billing application that implements the logic to deal
with different cases. Easiest one is when you have one STOP event, but
if you have more, then you have to check for reply code, cseq, etc...
Well, as I said I don't need dealing with it if I use radius ACC since only
one BYE matching the dialog can trigger a SQL STOP action (other BYE's
matching this dialog will trigger radius STOP action, but not SQL action due
to "WHERE" clausules the SQL query).
So the only I need is the proxy ensures that the BYE is not fraudulent, for
example, it's not a spoofed BYE from the user with RURI=same_user.
accounting only 200ok-ed BYEs will ensure that.

By the way, are you accounting all session updates, e.g., re-INVITE, or
just first INVITE and the BYE. There are billing systems that use the
re-INVITEs due to session timers to estimate the duration when BYE is
missing.
Post by Iñaki Baz Castillo
Anyway, it seems really complex and a post-accounting process should be needed
as you say. I will try to avoid needing it doing the billing in a B2BUA.
Don't you have a rating engine to compute the costs? Also, I assume you
have a tool to aggregate the cdrs from your providers with what you get
on proxy. Indeed, accounting/billing is quite complex, depending also on
what type of charging you have (e.g., time of the day based charging).

Would be interesting to see what would be more efficient, a b2bua that
may give better CDRs or a stand alone application that digest the
accounting events. It is clear that a b2bua introduces delays, therefore
reduces the processing capacity -- probably difference is not that big.

Cheers,
Daniel
--
Daniel-Constantin Mierla
http://www.asipto.com
Iñaki Baz Castillo
2008-12-22 14:33:41 UTC
Permalink
Post by Daniel-Constantin Mierla
Post by Iñaki Baz Castillo
Well, as I said I don't need dealing with it if I use radius ACC since
only one BYE matching the dialog can trigger a SQL STOP action (other BYE's
matching this dialog will trigger radius STOP action, but not SQL action due
to "WHERE" clausules the SQL query).
So the only I need is the proxy ensures that the BYE is not fraudulent,
for example, it's not a spoofed BYE from the user with RURI=same_user.
accounting only 200ok-ed BYEs will ensure that.
By the way, are you accounting all session updates, e.g., re-INVITE, or just
first INVITE and the BYE. There are billing systems that use the re-INVITEs
due to session timers to estimate the duration when BYE is missing.
Well, except in the case of BYE sent by the gateway (since the
attacker could reply non-200 to the BYE and mantain the session open).
But anyway, I imagine this exotica case:

- alice (attacker) speaking with the PSTN gateway.

- alice sends this BYE:

BYE sip:***@PSTN_GATEWAY SIP/2.0
Route: <sip:PROXY_IP>
Route: <sip:***@ALICE_PHONE_IP>

The proxy could check the RURI to know that the destination in the
gateway, so to account a BYE the gateway must reply 200 OK to the BYE.
The first route is the proxy, so there is loose routing (as expected
and required).
But there is other Route pointing to alice again, so the BYE would be
sent to alice who will reply 200 OK to this spoofed BYE.
The proxy would trigger STOP action but the call session remains.
Post by Daniel-Constantin Mierla
Post by Iñaki Baz Castillo
Anyway, it seems really complex and a post-accounting process should be
needed as you say. I will try to avoid needing it doing the billing in a
B2BUA.
Don't you have a rating engine to compute the costs? Also, I assume you have
a tool to aggregate the cdrs from your providers with what you get on proxy.
Indeed, accounting/billing is quite complex, depending also on what type of
charging you have (e.g., time of the day based charging).
Well, now I'm designing it, not a real implementation now.
Post by Daniel-Constantin Mierla
Would be interesting to see what would be more efficient, a b2bua that may
give better CDRs or a stand alone application that digest the accounting
events. It is clear that a b2bua introduces delays, therefore reduces the
processing capacity -- probably difference is not that big.
I think (but not 100% sure) that a B2BUA could check all the requests
in both legs to ensure that no spoofed accounting action is performed,
so the accounting would be in realtime (without the need of an
external application re-checking it).
But this is just theory XD


Thanks a lot for your comments.
--
Iñaki Baz Castillo
<***@aliax.net>
jh-lyJTu5r7LVPQT0dZR+ (Juha Heinanen)
2008-12-22 15:42:28 UTC
Permalink
Post by Iñaki Baz Castillo
Route: <sip:PROXY_IP>
in this particular case, you could call to_gw() and find out that
request is going to gw and, if so, drop the request it is has more than
one route header (the one for the proxy itself).

-- juha
Iñaki Baz Castillo
2008-12-22 16:05:30 UTC
Permalink
Post by jh-lyJTu5r7LVPQT0dZR+ (Juha Heinanen)
Post by Iñaki Baz Castillo
Route: <sip:PROXY_IP>
in this particular case, you could call to_gw() and find out that
request is going to gw and, if so, drop the request it is has more than
one route header (the one for the proxy itself).
Sure Juha, but don't you agree with me that finally there are too many
exotic checks?
Sincerely I can't expect that any user configuring a proxy for
accounting purposes will take all this "features" in mind.
--
Iñaki Baz Castillo
<***@aliax.net>
jh-lyJTu5r7LVPQT0dZR+ (Juha Heinanen)
2008-12-22 16:16:15 UTC
Permalink
Post by Iñaki Baz Castillo
Sure Juha, but don't you agree with me that finally there are too many
exotic checks?
i fully agree with that. that is why i have never even dreamed to do
any monetary accounting of sip calls. what my proxy provides is for
end user's "information only". trying to anything beyond that means
re-inventing pstn and loosing the benefits of internet. the "solution"
is called ims, and i don't want to be any part of it.

-- juha
Iñaki Baz Castillo
2008-12-22 16:19:04 UTC
Permalink
Post by jh-lyJTu5r7LVPQT0dZR+ (Juha Heinanen)
Post by Iñaki Baz Castillo
Sure Juha, but don't you agree with me that finally there are too many
exotic checks?
i fully agree with that. that is why i have never even dreamed to do
any monetary accounting of sip calls. what my proxy provides is for
end user's "information only". trying to anything beyond that means
re-inventing pstn and loosing the benefits of internet. the "solution"
is called ims, and i don't want to be any part of it.
100% agree :)
--
Iñaki Baz Castillo
<***@aliax.net>
Klaus Darilion
2008-12-23 08:26:39 UTC
Permalink
Post by jh-lyJTu5r7LVPQT0dZR+ (Juha Heinanen)
Post by Iñaki Baz Castillo
Route: <sip:PROXY_IP>
in this particular case, you could call to_gw() and find out that
request is going to gw and, if so, drop the request it is has more than
one route header (the one for the proxy itself).
Not sure if this is enough - the attacker could omit the Route header
pointing to the proxy. Maybe the check should use $dd which is set if
another Route header is present.

regard
klaus
Iñaki Baz Castillo
2008-12-23 09:47:43 UTC
Permalink
Post by Klaus Darilion
Post by jh-lyJTu5r7LVPQT0dZR+ (Juha Heinanen)
Post by Iñaki Baz Castillo
Route: <sip:PROXY_IP>
in this particular case, you could call to_gw() and find out that
request is going to gw and, if so, drop the request it is has more than
one route header (the one for the proxy itself).
Not sure if this is enough - the attacker could omit the Route header
pointing to the proxy. Maybe the check should use $dd which is set if
another Route header is present.
Yes, I think so. Checking $dd would be the appropiate way to know if
the request has other Route.
So steps would be:

a) The proxy receives BYE from a gateway IP, so it must account the
BYE in that moment (regardless of the BYE response).

b) The proxy receives BYE from a non gateway IP (so it could be an
user). It must:
- Check loose routing (as always).
- Check if $dd is set. In that case drop the request since it
shouldn't have more Route header and could be a spoofed BYE.
- If $dd is not set, then check if the RURI host:port matches an
IP:port of a gateway. If not, drop the request.
- Forward the request to the gateway.
- Upon receiving 200 OK from the gateway do the accounting (call end).

Do I miss somehting?
Is it *completely* feasible? or is it vulnerable with a more exotic BYE?
--
Iñaki Baz Castillo
<***@aliax.net>
jh-lyJTu5r7LVPQT0dZR+ (Juha Heinanen)
2008-12-23 10:41:10 UTC
Permalink
Post by Iñaki Baz Castillo
Do I miss somehting?
transport between proxy and gw should be tcp if gw is not in private
network with the proxy. otherwise ip based tests do not prove
anything.

-- juha
Klaus Darilion
2008-12-23 11:03:12 UTC
Permalink
Post by jh-lyJTu5r7LVPQT0dZR+ (Juha Heinanen)
Post by Iñaki Baz Castillo
Do I miss somehting?
transport between proxy and gw should be tcp if gw is not in private
network with the proxy. otherwise ip based tests do not prove
anything.
And if the GW is in the private network make sure to configure your
router to block incoming IP packets with local source IP address (don't
let spoofed packets into your network, Cisco reverse path filtering)

klaus
Iñaki Baz Castillo
2008-12-23 12:45:31 UTC
Permalink
Post by jh-lyJTu5r7LVPQT0dZR+ (Juha Heinanen)
transport between proxy and gw should be tcp if gw is not in private
network with the proxy. otherwise ip based tests do not prove
anything.
And if the GW is in the private network make sure to configure your router
to block incoming IP packets with local source IP address (don't let spoofed
packets into your network, Cisco reverse path filtering)
good point!
--
Iñaki Baz Castillo
<***@aliax.net>
Jiri Kuthan
2009-01-07 01:30:11 UTC
Permalink
there are way too many ways how routing logic can be confused to bypass
admission control. poisoning user loc, having a DNS name or ENUM entry
to point to a gateway (scripting fails to see it as PSTN target and
may skip PSTN ACLs), etc. a good thing to do is to use onsend_route
and check if someone is trying to use a gateway whilst a call is not
being recognized as to a gateway.

-jiri
Post by Klaus Darilion
Post by jh-lyJTu5r7LVPQT0dZR+ (Juha Heinanen)
Post by Iñaki Baz Castillo
Route: <sip:PROXY_IP>
in this particular case, you could call to_gw() and find out that
request is going to gw and, if so, drop the request it is has more than
one route header (the one for the proxy itself).
Not sure if this is enough - the attacker could omit the Route header
pointing to the proxy. Maybe the check should use $dd which is set if
another Route header is present.
regard
klaus
_______________________________________________
Users mailing list
http://lists.kamailio.org/cgi-bin/mailman/listinfo/users
Iñaki Baz Castillo
2009-01-07 08:54:08 UTC
Permalink
Post by Jiri Kuthan
there are way too many ways how routing logic can be confused to bypass
admission control. poisoning user loc, having a DNS name or ENUM entry
to point to a gateway (scripting fails to see it as PSTN target and
may skip PSTN ACLs), etc. a good thing to do is to use onsend_route
and check if someone is trying to use a gateway whilst a call is not
being recognized as to a gateway.
True. I implemented it with OpenSer address blacklists (containing the
gateways IP's). I just dissable this blacklist when a call goes to a
PSTN (I decide it by examinating the RURI). In case a user is
registered with a spoofed Contact like:
Contact: sip:+***@FACKED_DOMAIN_POINTING_TO_GW
then a call to this user will be rejected since the resolved
destination IP would match the blacklist.

Regards.
--
Iñaki Baz Castillo
<***@aliax.net>
Daniel-Constantin Mierla
2009-01-08 14:16:04 UTC
Permalink
Post by Iñaki Baz Castillo
Post by Jiri Kuthan
there are way too many ways how routing logic can be confused to bypass
admission control. poisoning user loc, having a DNS name or ENUM entry
to point to a gateway (scripting fails to see it as PSTN target and
may skip PSTN ACLs), etc. a good thing to do is to use onsend_route
and check if someone is trying to use a gateway whilst a call is not
being recognized as to a gateway.
True. I implemented it with OpenSer address blacklists (containing the
gateways IP's). I just dissable this blacklist when a call goes to a
PSTN (I decide it by examinating the RURI). In case a user is
then a call to this user will be rejected since the resolved
destination IP would match the blacklist.
this is falling in the same race as reliability (how many 9es?!?!).
Questions like how secure is the service and how accurate is the
accounting are answered with same phrase: how much do you want to invest in?

Probably you will never think of all cases that can occur. Very
important is to account everything goes on your platform and be able to
recover when local accounting records does not match with what you get
from your PSTN termination providers. Then you can correlate CDRs and
bill properly the user.

Cheers,
Daniel
--
Daniel-Constantin Mierla
http://www.asipto.com
Raúl Alexis Betancor Santana
2008-12-22 16:47:02 UTC
Permalink
Post by Iñaki Baz Castillo
Well, except in the case of BYE sent by the gateway (since the
attacker could reply non-200 to the BYE and mantain the session open).
- alice (attacker) speaking with the PSTN gateway.
Route: <sip:PROXY_IP>
The proxy could check the RURI to know that the destination in the
gateway, so to account a BYE the gateway must reply 200 OK to the BYE.
The first route is the proxy, so there is loose routing (as expected
and required).
But there is other Route pointing to alice again, so the BYE would be
sent to alice who will reply 200 OK to this spoofed BYE.
The proxy would trigger STOP action but the call session remains.
In all the thread I wonder why you allow users to speak with your GW's ... in
our systems users only may speak with our proxies, and our gateway only speak
with our proxies.
We know that this config overload the proxies, but powerfull machines are
cheaper that aspirine truks ;-)

If you route all your traffic throught you proxies (SIP signaling, I mean) and
you do your accounting based on your GW's information and not based on your
proxies information, you will be safe.

Best regards
--
Raúl Alexis Betancor Santana
Iñaki Baz Castillo
2008-12-22 16:58:12 UTC
Permalink
Post by Raúl Alexis Betancor Santana
In all the thread I wonder why you allow users to speak with your GW's ... in
our systems users only may speak with our proxies, and our gateway only speak
with our proxies.
Hi Raul, when I say "alice speaks with gateway" I always mean "alice
speaks with gateway *through* the proxy". :)
Post by Raúl Alexis Betancor Santana
If you route all your traffic throught you proxies (SIP signaling, I mean) and
you do your accounting based on your GW's information and not based on your
proxies information, you will be safe.
Sure, the problem is that it requires be the owner of the gateways.
--
Iñaki Baz Castillo
<***@aliax.net>
Raúl Alexis Betancor Santana
2008-12-22 19:34:03 UTC
Permalink
Post by Iñaki Baz Castillo
Post by Raúl Alexis Betancor Santana
In all the thread I wonder why you allow users to speak with your GW's
... in our systems users only may speak with our proxies, and our gateway
only speak with our proxies.
Hi Raul, when I say "alice speaks with gateway" I always mean "alice
speaks with gateway *through* the proxy". :)
Post by Raúl Alexis Betancor Santana
If you route all your traffic throught you proxies (SIP signaling, I
mean) and you do your accounting based on your GW's information and not
based on your proxies information, you will be safe.
Sure, the problem is that it requires be the owner of the gateways.
I know, you whant to have a "Man In The Middle" proxy, hidding to your
customers what are the real "gateways", that you don't own. That's ok .. when
I say "your own gateways", I mean ... "your own B2BUA's/PSTN Gateways" ...,
it's obvious that I prefer to proxy also the RTP throught "our gateways", so
we can have full control over RTP and no fraudulent use of our proxies are
allowed (if we did not something wrong ...)

I don't like doing accounting on the proxy at all, I prefer to do it in the
B2BUA/Gateways machines, realtime or quasi-realtime accounting, but not on
the proxy.
Iñaki Baz Castillo
2008-12-22 20:24:32 UTC
Permalink
Post by Raúl Alexis Betancor Santana
I don't like doing accounting on the proxy at all, I prefer to do it in the
B2BUA/Gateways machines, realtime or quasi-realtime accounting, but not on
the proxy.
Sure. As I've trying to state in this thread, I consider accounting in a proxy
very vulnerable.
--
Iñaki Baz Castillo
Klaus Darilion
2008-12-18 23:02:44 UTC
Permalink
my 2 cents:

1. nice attack ;-)

2. perform accounting only on a dialog statefull node

2.1 the gateway is the most accurate accounting source

2.2 if you need proxy based accounting use a media relay which you
disable on BYE

regards
klaus
Post by Iñaki Baz Castillo
Hi, first of all I'm sorry for this cross-posting, but I think it
could be interesting for any SIP proxy with accounting capabilities.
I'm thinking in the following flow in which the caller/attacker would
--------------------------------------------------------------------------
attacker Kamailio (Acc) gateway
INVITE (CSeq 12) ------>
<-------- 407 Proxy Auth
INVITE (CSeq 13) ------>
INVITE (CSeq 13) ------>
<------------------- 200 Ok
<------------------- 200 Ok
<< Acc START >>
ACK (CSeq 13) ----------->
ACK (CSeq 13) ----------->
<******************* RTP ************************>
# Fraudulent BYE !!!
BYE (CSeq 10) ----------->
<< Acc STOP >>
BYE (CSeq 10) ----------->
<-- 500 Req Out of Order
<-- 500 Req Out of Order
--------------------------------------------------------------------------
The call hasn't finished, but Kamailio has ended the accounting for
this call since it received a BYE. And this BYE will generate a
correct ACC Stop action (since it matches From_tag, To_tag and
Call-ID).
I think this is *VERY* dangerous and I hope I'm wrong.
Would help the dialog module here? does the dialog module check the
CSeq of the BYE in some way and could it prevent Kamailio from
generating the ACC STOP action? (I don't think so).
I've also asked in SIP-implementors and an idea could be generating
the ACC STOP action when receiving the 200 OK for the BYE (and not
when receiving the BYE itself). Of course this will be valid when the
gateway is the recipient of the BYE (and we know the gateway is not an
"attacker"), but this is not valid when the recipient of the BYE is an
user since it could send no reply for the BYE.
- Using the dialog module, Kamailio should check the CSeq value in the BYE.
1) Kamailio should forward the BYE just in case the CSeq is higher
than the actual CSeq for this dialog direction.
2) Kamailio should generate the ACC STOP action just in case the CSeq
is higher than the actual CSeq for this dialog direction.
Both 1) and 2) are needed since a gateway could accept a BYE with
wrong CSeq. In this case the call is ended but the accounting STOP
action doesn't exist (infinite call).
But I think this is too complex, isn't it?
Daniel-Constantin Mierla
2008-12-20 09:33:03 UTC
Permalink
Hello,
Post by Klaus Darilion
1. nice attack ;-)
2. perform accounting only on a dialog statefull node
2.1 the gateway is the most accurate accounting source
2.2 if you need proxy based accounting use a media relay which you
disable on BYE
I think that for some particular cases, a two-step accounting is a good
solution. Like:
- request fwd'ed
- reply fwd'ed

I am thinking when one is willing to account MESSAGEs for example. Once
forwarded, the service is delivered. If you restart the proxy, then
200OK won't match an active transaction.

The second step could be just a log message somewhere, when it happens a
corner case like no active transaction, so additional tools can recover
proper billing records (here special security checks have to be applied
anyhow).

I agree with you, that best place for acc is the gateway. Some times the
service involves more than audio calls, so more things need to be
accounted, on the proxy.

Cheers,
Daniel
Post by Klaus Darilion
regards
klaus
Post by Iñaki Baz Castillo
Hi, first of all I'm sorry for this cross-posting, but I think it
could be interesting for any SIP proxy with accounting capabilities.
I'm thinking in the following flow in which the caller/attacker would
--------------------------------------------------------------------------
attacker Kamailio (Acc) gateway
INVITE (CSeq 12) ------>
<-------- 407 Proxy Auth
INVITE (CSeq 13) ------>
INVITE (CSeq 13) ------>
<------------------- 200 Ok
<------------------- 200 Ok
<< Acc START >>
ACK (CSeq 13) ----------->
ACK (CSeq 13) ----------->
<******************* RTP ************************>
# Fraudulent BYE !!!
BYE (CSeq 10) ----------->
<< Acc STOP >>
BYE (CSeq 10) ----------->
<-- 500 Req Out of Order
<-- 500 Req Out of Order
--------------------------------------------------------------------------
The call hasn't finished, but Kamailio has ended the accounting for
this call since it received a BYE. And this BYE will generate a
correct ACC Stop action (since it matches From_tag, To_tag and
Call-ID).
I think this is *VERY* dangerous and I hope I'm wrong.
Would help the dialog module here? does the dialog module check the
CSeq of the BYE in some way and could it prevent Kamailio from
generating the ACC STOP action? (I don't think so).
I've also asked in SIP-implementors and an idea could be generating
the ACC STOP action when receiving the 200 OK for the BYE (and not
when receiving the BYE itself). Of course this will be valid when the
gateway is the recipient of the BYE (and we know the gateway is not an
"attacker"), but this is not valid when the recipient of the BYE is an
user since it could send no reply for the BYE.
- Using the dialog module, Kamailio should check the CSeq value in the BYE.
1) Kamailio should forward the BYE just in case the CSeq is higher
than the actual CSeq for this dialog direction.
2) Kamailio should generate the ACC STOP action just in case the CSeq
is higher than the actual CSeq for this dialog direction.
Both 1) and 2) are needed since a gateway could accept a BYE with
wrong CSeq. In this case the call is ended but the accounting STOP
action doesn't exist (infinite call).
But I think this is too complex, isn't it?
_______________________________________________
Users mailing list
http://lists.kamailio.org/cgi-bin/mailman/listinfo/users
--
Daniel-Constantin Mierla
http://www.asipto.com
Iñaki Baz Castillo
2008-12-20 10:03:05 UTC
Permalink
Post by Iñaki Baz Castillo
I'm thinking in the following flow in which the caller/attacker would
--------------------------------------------------------------------------
attacker Kamailio (Acc) gateway
INVITE (CSeq 12) ------>
<-------- 407 Proxy Auth
INVITE (CSeq 13) ------>
INVITE (CSeq 13) ------>
<------------------- 200 Ok
<------------------- 200 Ok
<< Acc START >>
ACK (CSeq 13) ----------->
ACK (CSeq 13) ----------->
<******************* RTP ************************>
# Fraudulent BYE !!!
BYE (CSeq 10) ----------->
<< Acc STOP >>
BYE (CSeq 10) ----------->
<-- 500 Req Out of Order
<-- 500 Req Out of Order
--------------------------------------------------------------------------
There is a solution for this (not perfect):

- The proxy stops the accounting when receives a BYE from the gateway,
regardless of the BYE reply from the client. This prevents from BYE
negatively answered by clients.
- The proxy stops the accounting when receives a BYE from the client and the
200 OK from the gateway. This prevents from the above case in which the
client sends an out-of-date CSeq in the BYE.


But this is not enough, note the following case:

- The user is in a call with the gateway.
- The user sends a BYE with "Route: proxy" and RURI pointing to *himself*.
- The BYE arrives to the proxy which forwards it back to the user again.
- The user (attacker in fact) replies a 200 OK but doesn't terminate the RTP
session with the gateway.
- The proxy receives the 200 OK (BYE) from a user, so terminates the
accounting.
- The gateway knows exactly *nothing* about it, the call continues (but from
now it's free).

Annoying?
--
Iñaki Baz Castillo
Daniel-Constantin Mierla
2008-12-20 10:52:28 UTC
Permalink
Post by Iñaki Baz Castillo
Post by Iñaki Baz Castillo
I'm thinking in the following flow in which the caller/attacker would
--------------------------------------------------------------------------
attacker Kamailio (Acc) gateway
INVITE (CSeq 12) ------>
<-------- 407 Proxy Auth
INVITE (CSeq 13) ------>
INVITE (CSeq 13) ------>
<------------------- 200 Ok
<------------------- 200 Ok
<< Acc START >>
ACK (CSeq 13) ----------->
ACK (CSeq 13) ----------->
<******************* RTP ************************>
# Fraudulent BYE !!!
BYE (CSeq 10) ----------->
<< Acc STOP >>
BYE (CSeq 10) ----------->
<-- 500 Req Out of Order
<-- 500 Req Out of Order
--------------------------------------------------------------------------
- The proxy stops the accounting when receives a BYE from the gateway,
regardless of the BYE reply from the client. This prevents from BYE
negatively answered by clients.
- The proxy stops the accounting when receives a BYE from the client and the
200 OK from the gateway. This prevents from the above case in which the
client sends an out-of-date CSeq in the BYE.
- The user is in a call with the gateway.
- The user sends a BYE with "Route: proxy" and RURI pointing to *himself*.
- The BYE arrives to the proxy which forwards it back to the user again.
- The user (attacker in fact) replies a 200 OK but doesn't terminate the RTP
session with the gateway.
- The proxy receives the 200 OK (BYE) from a user, so terminates the
accounting.
- The gateway knows exactly *nothing* about it, the call continues (but from
now it's free).
Annoying?
This is part of well know Route-based attacks. I did a demo for a German
newspaper like 4-5 years ago with a modified KPhone.

Fortunately for you, kamailio gives you a lot of tools to enhance the
security as you need. You can check the stack of Via headers, source ip,
etc... against the destionation address.

Similar attacks can happen with poisoned DNS, where is hard to check the
IP address.

I believe in this cases an important aspect is to be sure you can
identify the attacker. It is hard to prevent all people can think of,
but when detecting one case, being able to get the guilty is very
important. Also, at that time, you can add the logic to prevent further
exposure to same attack.

Cheers,
Daniel
--
Daniel-Constantin Mierla
http://www.asipto.com
jh-lyJTu5r7LVPQT0dZR+ (Juha Heinanen)
2008-12-20 15:19:00 UTC
Permalink
Post by Daniel-Constantin Mierla
I believe in this cases an important aspect is to be sure you can
identify the attacker. It is hard to prevent all people can think of,
but when detecting one case, being able to get the guilty is very
important. Also, at that time, you can add the logic to prevent further
exposure to same attack.
this sounds like the ever lasting story of fixing security holes in
internet explorer. i don't think it is a vice path to take.

better to proxy all media if accounting cannot be done in the
gateways. and then we have reinvented pstn ...

-- juha
Daniel-Constantin Mierla
2008-12-21 08:02:18 UTC
Permalink
Post by jh-lyJTu5r7LVPQT0dZR+ (Juha Heinanen)
Post by Daniel-Constantin Mierla
I believe in this cases an important aspect is to be sure you can
identify the attacker. It is hard to prevent all people can think of,
but when detecting one case, being able to get the guilty is very
important. Also, at that time, you can add the logic to prevent further
exposure to same attack.
this sounds like the ever lasting story of fixing security holes in
internet explorer.
:-)
Post by jh-lyJTu5r7LVPQT0dZR+ (Juha Heinanen)
i don't think it is a vice path to take.
better to proxy all media if accounting cannot be done in the
gateways. and then we have reinvented pstn ...
you are right with media based session and calls to gateways, but
sometime could be the case of accounting other types of sessions/sip
messages. When the value is transmitted via signaling, that has to be
stored somehow, b2bua is ultimate solution and the safest.

Cheers,
Daniel
--
Daniel-Constantin Mierla
http://www.asipto.com
jh-lyJTu5r7LVPQT0dZR+ (Juha Heinanen)
2008-12-21 08:09:48 UTC
Permalink
Post by Daniel-Constantin Mierla
When the value is transmitted via signaling, that has to be
stored somehow, b2bua is ultimate solution and the safest.
i agree with that (which was also inaki's proposal). but even with
b2bua, problem arises if b2bua crashes and becomes unavailable for a
moment or after crash looses its state.

-- juha
Daniel-Constantin Mierla
2008-12-21 08:21:25 UTC
Permalink
Post by jh-lyJTu5r7LVPQT0dZR+ (Juha Heinanen)
Post by Daniel-Constantin Mierla
When the value is transmitted via signaling, that has to be
stored somehow, b2bua is ultimate solution and the safest.
i agree with that (which was also inaki's proposal). but even with
b2bua, problem arises if b2bua crashes and becomes unavailable for a
moment or after crash looses its state.
indeed. That's why I proposed multi-step accounting on proxy:
- request in/out
- reply in/out
While may not solve all known/unknown cases, it offers extra information
that can be used to recover damages.

Cheers,
Daniel
--
Daniel-Constantin Mierla
http://www.asipto.com
jh-lyJTu5r7LVPQT0dZR+ (Juha Heinanen)
2008-12-20 15:14:48 UTC
Permalink
Post by Iñaki Baz Castillo
- The gateway knows exactly *nothing* about it, the call continues (but from
now it's free).
Annoying?
it is only if you try to do accounting in the proxy. if you do
accounting in the gateway, the call continues, but is not free.

lots of effort has gone to implement reliable accounting of sip calls in
the proxy. i personally don't think that it is a good idea, because it
greatly complicates proxy implementation and may force proxying of media
even if it would not otherwise be needed.

-- juha
Iñaki Baz Castillo
2008-12-20 17:53:38 UTC
Permalink
Post by jh-lyJTu5r7LVPQT0dZR+ (Juha Heinanen)
Post by Iñaki Baz Castillo
- The gateway knows exactly *nothing* about it, the call continues (but
from now it's free).
Annoying?
it is only if you try to do accounting in the proxy. if you do
accounting in the gateway, the call continues, but is not free.
lots of effort has gone to implement reliable accounting of sip calls in
the proxy. i personally don't think that it is a good idea, because it
greatly complicates proxy implementation and may force proxying of media
even if it would not otherwise be needed.
What about doing the accounting in a B2BUA (just SIP signalling, no media)?
At least a B2BUA is fully dialog stateful (it really knows about CSeq values
and so).
--
Iñaki Baz Castillo
jh-lyJTu5r7LVPQT0dZR+ (Juha Heinanen)
2008-12-20 18:15:36 UTC
Permalink
Post by Iñaki Baz Castillo
What about doing the accounting in a B2BUA (just SIP signalling, no media)?
At least a B2BUA is fully dialog stateful (it really knows about CSeq values
and so).
that might work. using sems, for example, the b2bua could just be on
the signalling path and let media flow directly.

-- juha
Loading...