RADIUSを使用したFreeSWITCHでのVoIPカードプラットフォームの実装

タスクは、ラック内の古いジャンクを取り除き、通常は特別なアクセス番号を呼び出してPINコードを入力することにより、他のオペレーターの加入者に長距離/国際通信を提供するために、わずかに忘れられたがまだ存在する技術のソフトウェアバージョンを実装することでした 加入者認証はRADIUSを介して請求を通過し、そこにコールレコードが追加されます。



プラットフォーム自体は誰にとってもあまり興味がありませんが、設定を書いたとき、使用例が本当に不足していました。この例が誰かに役立つことを願っています。



私の仕事は表面的に電話に関連しているだけなので、アスタリスクにあまり馴染みがないため、ベースプラットフォームを選択する際に制限や偏見はありませんでした。 特に企業での積極的な使用を考慮して、すべてをアスタリスクに実装することは論理的ですが、苦い経験によると、その失敗は最も不適切な瞬間に発生し、サービスの単純な再起動は役に立ちません。 したがって、肯定的なレビューとレビューを読んで、プラットフォームはFreeSWITCHに選ばれました。 ロシア語のドキュメントは確かに少なくなりましたが、怖くはありませんでした。日没h323のアスタリスクがいくつかのパッケージから組み立てられた方法をよく覚えているからです。厳密に一致するバージョンとインストール例はわずかでした。 セットアッププロセスの前およびセットアップ中に、 Wikiは慎重に研究されました。



問題の声明



特に携帯電話事業者の関税よりも長距離電話をかけたい人が多くいます。電話や「8区」へのアクセスがない勤務先番号からのアプリケーションはありません。 これを行うには、アクセス番号(または複数)を整理します。クライアントは(555555以降)に電話をかけ、承認(発信者IDまたはPINコードによる)を渡し、現在の資金残高を聞き、電話番号をダイヤルします。 実際、これらすべては、古くから(そして非常に人気のあるサービスであった)巨大で恐ろしいCisco AS5300ですでに機能しています。 発信者IDによる承認の批判を予測:プリペイドシステムと大きな残高はありません-リスクは最小限で、顧客はほとんどいません-無料で通話できる発信者IDを推測したり、VoIPで呼び出したり、番号を変更したりするのは無意味です-そのような通話からの利益は最小限で、ローカルオペレーターを追跡するのは簡単です。



サービス図のようなもので、右側の数字は拡張機能の表現です。







複雑なことは何もありませんが、いじくり回さなければなりませんでした。

  1. xmlの構成の形式は、管理者にはまったく馴染みがありませんが、最初にそれらを含める論理は非常に混乱しているように見えます。
  2. 条件条件の非常に珍しいロジック、特に、break = "on-true"(実際にプログラムの実行を中断するにはどうすればよいか)に常に困惑しました。この問題を慎重に研究することをお勧めします。 要するに、ブレークはハンティングプロセス(少し低いハンティングについて)にのみ影響し、条件が(true)である場合(true)、一致しない場合(false)またはまったく中断せずに次の条件を処理する場合は、現在の拡張機能の条件の処理を中断します(決してしない) )
  3. inline = "true"を設定できるプリミティブな計算を除くすべての計算は、transferまたはexecute_extensionの後にのみ実行されます。 要点は、FSがXML_Dialplanをハンティングと実行(ハンティングと実行)の2段階で処理することです。 ハント中に、条件、アクション、およびアンチアクションが実行され、実行するアプリケーションが選択されます。 したがって、複雑なアプリケーションの結果を取得する必要がある場合は、別の拡張機能に切り替える必要があります。
  4. 正規表現を使用せずに文字列に何かを取り込んで置き換えることはできません。また、単純な初等代数関数がないため非常に混乱しています。
  5. 特にモジュールに関するドキュメントは非常に少ないです(4月に修正された機能の叙事詩的な説明がありました:このアプリの機能がわからない場合は、使用しないでください!:))。




解決策



FSのインストールについては説明しません。そこでは、標準に加えてすべてが簡単です。さらに、不足しているモジュールをコンパイルするだけで済みます。 すべてのパスは、FSがインストールされているフォルダーに関連して示されます。



設定のために、別の番号が割り当てられ、FSに送信されました(外部サーバーからの呼び出し時に非標準ポートを使用する機能があります-5080)。 conf / sip_profiles / external / sipgate.xmlのsipgate(IPアドレス10.10.10.10)と呼ばれるサーバーを介して、発信呼び出し用のプロファイルを作成します(パブリックコンテキストで正しい内線番号を受信するため)。



<include> <gateway name="sipgate"> <param name="username" value="<  >"/> <param name="proxy" value="10.10.10.10"/> <param name="register" value="false"/> <param name="caller-id-in-from" value="true"/> </gateway> </include>
      
      







さらなる作業のために、FSをRussifyする必要があり、フォルダsound / ru / RU / elenaは、私の場合は8000( archive with files )の目的のビットレートのサウンドファイルで満たされていました。 freeswitch.xmlで、enをruに変更します。



 <section name="languages" description="Language Management"> <!-- <X-PRE-PROCESS cmd="include" data="lang/en/*.xml"/>--> <X-PRE-PROCESS cmd="include" data="lang/ru/*.xml"/> </section>
      
      







音声ファイルは標準で使用されていて十分ではありませんでしたが、録音は依然として問題です。

dialplan / public.xml構成は最大限にトリミングされています。



 <include> <context name="public"> <extension name="unloop"> <condition field="${unroll_loops}" expression="^true$"/> <condition field="${sip_looped_call}" expression="^true$"> <action application="deflect" data="${destination_number}"/> </condition> </extension> <X-PRE-PROCESS cmd="include" data="public/*.xml"/> </context> </include>
      
      







そして、ファイルconf / dialplan / public / voip_public.xmlに、着信コール用の拡張機能を記述します。ここで、すぐに番号で認証を試みます。



 <include> <extension name="voip_platform_pub_step1"> <condition field="destination_number" expression="^(555555)$"> <!--          --> <action application="log" data="INFO pub/1 RAD_AUTH STEP1"/> <action application="set" data="process_cdr=b_only"/><!--   Stop accounting    , ..      ,    Start  -    ... --> <action inline="true" application="set" data="pin_auth_count=0"/><!--     ,        -   --> <!--     radius  --> <action inline="true" application="set" data="CALLID=${uuid}"/> <action inline="true" application="set" data="CALLINGNUMBER=${caller_id_number}"/> <action inline="true" application="set" data="USERNAME=${caller_id_number}"/> <action inline="true" application="set" data="STEP=fs1"/><!--      (     ) --> <action application="auth_function" data="in ${CALLEDNUMBER}, in ${USERNAME}, in ${PASSWD}, out AUTH_RESULT"/><!--    radius,    ../../autoload_configs/rad_auth.conf.xml --> <action application="log" data="INFO pub/1 AUTH_RESULT=${AUTH_RESULT}: credit_amount=${credit_amount}; return_code=${return_code}"/> <action application="set" data="domain_name=$${domain}"/> <action application="transfer" data="10 XML voip"/><!--         --> </condition> </extension> </include>
      
      







「STEP = fs1」への個別の注意-私の場合は、請求書に、フラグfs1を使用した発信者IDによる承認と、PIN fs1pinによる承認を伝える方が便利でした。



コメントには、conf / autoload_configs / rad_auth.conf.xml(RADIUSサーバー10.20.20.20のIPアドレス)が記載されています。



 <configuration name="rad_auth.conf" description="radius authentification module"> <settings> </settings> <client> <param name="authserver" value="10.20.20.20:1812:radiussecret"/> <param name="dictionary" value="/usr/local/etc/radiusclient/dictionary.all"/> <param name="seqfile" value="/var/run/radius.seq"/> <param name="mapfile" value="/usr/local/etc/radiusclient/port-id-map"/> <param name="default_realm" value=""/> <param name="radius_timeout" value="3"/> <param name="radius_retries" value="2"/> <param name="radius_deadtime" value="0"/> <param name="bindaddr" value="*"/> </client> <vsas> <!--name= , id=   dictionary, value=    , pec=  dictionary, expr=       , direction=  --> <param name="Acct-Session-Id" id="44" value="CALLID" pec="0" expr="1" direction="in"/> <param name="Freeswitch-Ani" id="8" value="CALLINGNUMBER" pec="27880" expr="1" direction="in"/> <param name="Freeswitch-Dst" id="5" value="CALLEDNUMBER" pec="27880" expr="1" direction="in"/> <param name="NAS-Port-Type" id="61" value="0" pec="0" expr="0" direction="in"/> <param name="Connect-Info" id="77" value="STEP" pec="0" expr="1" direction="in"/> <param name="CREDIT_AMOUNT" id="101" value="credit_amount" pec="9" expr="0" direction="out"/> <param name="CREDIT_TIME" id="102" value="credit_time" pec="9" expr="0" direction="out"/> <param name="RADIUS_RETURN_CODE" id="103" value="return_code" pec="9" expr="0" direction="out"/> </vsas> </configuration>
      
      







そして今、記事の冒頭のスキームに従って、conf / dialplan / voip.xmlファイルのすべてのメインロジック:



 <?xml version="1.0" encoding="utf-8"?> <include> <context name="voip"> <extension name="unloop"> <condition field="${unroll_loops}" expression="^true$"/> <condition field="${sip_looped_call}" expression="^true$"> <action application="deflect" data="${destination_number}"/> </condition> </extension> <extension name="voip_10"> <condition field="destination_number" expression="^10$" break="on-false"/> <condition field="${AUTH_RESULT}" expression="^OK$" break="on-true"> <!--   IVR   dtmf  --> <action application="log" data="INFO voip_10 AUTH_RESULT=${AUTH_RESULT} => Read DTMF"/> <action application="answer"/> <action application="sleep" data="1000"/> <action application="play_and_get_digits" data="6 20 5 30000 # phrase:voip_get_digits voicemail/vm-fail_auth.wav digits ^\**(\d{6}|\d{10,20})\**$ 5000"/><!-- <min> <max> <tries> <timeout> <terminators> <file> <invalid_file> <var_name> <regexp> <digit_timeout> --> <action application="transfer" data="20 XML voip"/> </condition> <condition field="${return_code}" expression="^h323-return-code=6$" break="on-true"> <!--      =>      --> <action application="log" data="INFO voip_10 RETURN_CODE = 6 => Closed account"/> <action application="answer"/> <action application="sleep" data="1000"/> <!--TODO!!!      --> <action application="playback" data="voicemail/vm-not_available.wav"/> <action application="hangup" data="NORMAL_CLEARING"/> </condition> <!--TODO!!!     --> <condition field="${pin_auth_count}" expression="^0$" break="on-true"><!--        --> <!--         ,  PIN --> <action inline="true" application="set" data="pin_auth_count=1"/> <action application="log" data="INFO voip_10 RETURN_CODE = OTHER"/> <action application="answer"/> <action application="sleep" data="1000"/> <action application="play_and_get_digits" data="10 10 5 30000 # phrase:voip_get_pin conference/conf-bad-pin.wav pin ^(\d{10})$ 5000"/><!-- <min> <max> <tries> <timeout> <terminators> <file> <invalid_file> <var_name> <regexp> <digit_timeout> --> <action application="transfer" data="15 XML voip"/> </condition> <condition> <!--      ,        ,       PIN-,     PIN-     --> <action application="log" data="INFO voip_10 Prevent second PIN authentification"/> <action application="answer"/> <action application="sleep" data="1000"/> <!--TODO!!!         --> <action application="playback" data="voicemail/vm-not_available.wav"/> <action application="hangup" data="NORMAL_CLEARING"/> </condition> </extension> <extension name="voip_15"> <condition field="destination_number" expression="^15$"/> <condition field="${pin}" expression="^(\d{6})(\d{4})$"> <!--      PIN- --> <action application="log" data="INFO voip_15 pin=($1+$2) => RAD_AUTH STEP1/PIN"/> <action inline="true" application="set" data="CALLINGNUMBER=${caller_id_number}"/> <action inline="true" application="set" data="USERNAME=$1"/> <action inline="true" application="set" data="PASSWD=$2"/> <action inline="true" application="set" data="STEP=fs1pin"/> <action application="log" data="INFO voip_15 CALLID=${CALLID}; CALLINGNUMBER=${CALLINGNUMBER}; USERNAME=${USERNAME}"/> <action application="auth_function" data="in ${CALLEDNUMBER}, in ${USERNAME}, in ${PASSWD}, out AUTH_RESULT"/> <action application="log" data="INFO voip_15 AUTH_RESULT=${AUTH_RESULT}: credit_amount=${credit_amount}; return_code=${return_code}"/> <action application="transfer" data="10 XML voip"/><!--               --> </condition> </extension> <extension name="voip_20"> <condition field="destination_number" expression="^20$"/> <condition field="${digits}" expression="^\**(\d+)\**$"> <!--         --> <action inline="true" application="set" data="digits=$1"/> <action inline="true" application="set" data="digits=${regex(${digits}|^(\d{6})$|83532%1)}"/><!--  85555 –          ^(\d{6})$  ,      --> <action application="log" data="INFO voip_20 DTMF digits=${digits} => RAD_AUTH STEP2"/> <action application="log" data="INFO voip_20 CALLID=${CALLID}; CALLINGNUMBER=${CALLINGNUMBER}; USERNAME=${USERNAME}"/> <action inline="true" application="set" data="CALLEDNUMBER=${digits}"/> <!--       fs2pin  fs2 --> <action inline="true" application="set" data="STEP=${regex(${STEP}|^fs\d(.*)$|fs2%1)}"/> <action application="auth_function" data="in ${CALLEDNUMBER}, in ${USERNAME}, in ${PASSWD}, out AUTH_RESULT"/> <action application="log" data="INFO voip_20 AUTH_RESULT=${AUTH_RESULT}: credit_amount=${credit_amount}; credit_time=${credit_time}; return_code=${return_code}"/> <!--            --> <action application="export" data="nolocal:api_on_answer=sched_hangup +${credit_time} ${uuid} alloted_timeout" /> <action application="transfer" data="30 XML voip"/> </condition> </extension> <extension name="voip_30"> <condition field="destination_number" expression="^30$" break="on-false"/> <condition field="${AUTH_RESULT}" expression="^OK$" break="on-true"> <action application="log" data="INFO voip_30 AUTH_RESULT=${AUTH_RESULT} => Call number"/> <action inline="true" application="set" data="effective_caller_id_number=35555555555"/> <!--      (|)    (fs2|fs2pin),     Freeswitch-CLID   --> <action inline="true" application="set" data="effective_caller_id_name=${STEP}"/> <!--     USERNAME    ,   mod_radius_cdr        User-Name   --> <action application="export" data="nolocal:acc_username=${USERNAME}"/> <!-- <action application="set_profile_var" data="Caller-Username=${USERNAME}"/>         mod_radius_cdr,         --> <action application="set" data="hangup_after_bridge=true"/><!--  !     --> <action application="bridge" data="sofia/gateway/sipgate/${digits}"/> <!--TODO!!!    --> <action application="log" data="INFO voip_30 AFTER BRIDGE"/> </condition> <!--TODO!!!        ,    .. --> <!--TODO!!! h323-return-code=9 Access denied -     ,        --> <condition> <action application="log" data="INFO voip_30 RETURN_CODE = OTHER"/> <action application="answer"/> <action application="sleep" data="1000"/> <action application="playback" data="zrtp/zrtp-status_error.wav"/> <action application="hangup" data="NORMAL_CLEARING"/> </condition> </extension> </context> </include>
      
      







記載されているフレーズ:voip_get_digitsおよびフレーズ:voip_get_pin-入力を待っている間にクライアントに言われる「フレーズ」。2番目のフレーズはそれなしで実行できます。 conf / lang / ru / viop.xmlに保存されます:



 <include> <macro name="voip_get_digits" pause="250"> <input pattern="(.*)"> <match> <action function="play-file" data="ivr/ivr-account_balance_is.wav"/> <action function="say" data="${credit_amount}" method="pronounced" type="currency"/> <action function="play-file" data="ivr/ivr-please_enter_the_phone_number.wav"/> </match> </input> </macro> <macro name="voip_get_pin" pause="250"> <input pattern="(.*)"> <match> <action function="play-file" data="ivr/ivr-please_enter_pin_followed_by_pound.wav"/> <action function="execute" data="sleep(1000)"/> </match> </input> </macro> </include>
      
      







また、conf / autoload_configs / mod_radius_cdr.conf.xml configもあります。実際には何も設定されておらず、実際にはすべてのロジックがコードにハードコーディングされています。



 <configuration name="mod_radius_cdr.conf" description="RADIUS CDR Configuration"> <settings> <param name="dictionary" value="/usr/local/etc/radiusclient/dictionary.all"/> <param name="seqfile" value="/var/run/radius.seq"/> <param name="acctserver" value="10.20.20.20:1813:radiussecret"/> <param name="radius_retries" value="2"/> <param name="radius_timeout" value="3"/> <param name="radius_deadtime" value="0"/> </settings> </configuration>
      
      







統計は番号またはログインのいずれかでダンプする必要があるため、このモジュールのコードをわずかに変更する必要がありましたが、使用される許可のフラグを使用して通常の手段を使用してこのモジュールをパススルーする方法が見つかりませんでした。



その結果、すべてが機能していたときに、最終的なログ/ freeswitch.xml.fsxml構成を削減するために、一般的なFS構成が厳しく去勢されました。

テキストによると、ブザーはありますが、ブザーなしではすべてが機能しますが、ブザーを作成するとより美しくなります。



All Articles