MultiHomed Linuxルーターを構成するスクリプト

ただし、本格的なシステム管理者ではないため、ゲートウェイを構成する必要がしばしば発生します。 これまでのところ、外部インターフェースは1つしかありませんでした。これは、インターネットとlartc.comでコンパイルされた比較的普遍的なbashスクリプトを変更しただけです。 2つのインターネットプロバイダーにオプションがあったとき-変更を容易にするためにグループ化された設定でスクリプトを書くことができました。
スクリプトは次のことができます。

説明


メインのpythonスクリプトは、それ自体の設定に従って、実行されるbashスクリプトを形成するように配置されています。 このようなトリックは無視できないほど重く、声を出すのに十分ではないという理由で判明しました。 リンクの設定でスクリプトをダウンロードします。
そして、ここで彼のデバイスが説明されています。

設定


Python msr_ip.pyスクリプトは、必要な入力行で始まります。
#!/ usr / bin / env python
#-*-コーディング:utf-8-*-

#設定はこちら


次に、設定のストリーム、最初にインターフェースの説明が続きます。
ifaces = [
{
"dev" : "eth1" 、
「ip」 : 「192.168.0.1」 、
「ロール」 : 「ローカル」
} 、
{
"dev" : "eth2"
} 、
{
"dev" : "eth3" 、
「ip」 : 「1.2.3.4」 、
"gw" : "1.2.3.1" 、
"table" : "NewComPort" 、
「マーク」 : 「0x2」 、
「ロール」 : 「外部」 、
「重量」 : 7
} 、
{
"dev" : "ppp0" 、
"gw" : "5.6.7.1" 、
"table" : "velnet" 、
「マーク」 : 「0x1」 、
「ロール」 : 「外部」 、
「重量」 : 3
} 、
{
"dev" : "tun0" 、
「ip」 : 「192.168.1.1」 、
「テーブル」 : 「VPN」 、
「マーク」 : 「0x4」 、
「ロール」 : 「ローカル」
}
]

インターフェイスでは、実際には辞書要素である次のプロパティを使用できます。
dev-インターフェイス名、唯一の必須要素。
gw-ゲートウェイ。
table-ルーティングテーブルの番号または名前。名前が指定されている場合は、ファイル/ etc / iproute2 / rt_tablesに既に存在する必要があります。 外部インターフェイスには必須。
mark-パッケージのラベル。使用する独自のルールを追加する場合に使用します。
ロール -ロール。外部、ローカル、またはなし。 外部の場合-インターフェイスはそれぞれ外部と見なされ、NATを実行し、外部からの新しい接続を受け入れません。 ローカルの場合-インターフェイスはローカル:NATであり、外部への新しい接続を作成できます。
weight-ルートベースのアウトバウンド負荷分散の重み。
外部インターフェイスが上げられない場合、デフォルトルートにはリストされません。
次に、開いたり転送したりする必要があるポートについて説明します。
ポート= [
{
"proto" : "tcp" 、
"tPort" : 22 、
"sHost" : なし 、
「nPort」 : なし 、
「dHost」 : なし
}
、
{ #プロトコル全体をすぐに有効化
"proto" : "icmp" 、
"tPort" : なし 、
"sHost" : なし 、
「nPort」 : なし 、
「dHost」 : なし
}
、
{ #RDPをインターネットから192.168.0.3のLANに転送する
"proto" : "tcp" 、
"tPort" : 3389 、
"sHost" : なし 、
「nPort」 : 3389 、
「dHost」 : 「192.168.0.3」
}
、
{ #ポートを3390に変更したインターネットからRDPを192.168.0.2のLANに転送
"proto" : "tcp" 、
"tPort" : 3390 、
"sHost" : なし 、
「nPort」 : 3389 、
「dHost」 : 「192.168.0.2」
}
、
{ #1つのリモートホストのみからのWebコントロール
"proto" : "tcp" 、
「tPort」 : 80 、
"sHost" : "9.8.7.6" 、
「nPort」 : なし 、
「dHost」 : なし
}
、
{ #皆のためのopenVPN
"proto" : "tcp" 、
"tPort" : 1194 、
"sHost" : なし 、
「nPort」 : なし 、
「dHost」 : なし
}
]

例からすべてが明確になりますが、順序については説明します。
proto-プロトコル。
tPort-開く外部ポート。
sHost-必要に応じて、送信元アドレスへの制限。
nPort-転送中の新しいポート。
dHost-ポートが転送されるホスト。

これで、ノードを外部インターフェイスにバインドするためにルールが使用されます。
ルール= [
{ #ゲートウェイを介したプロバイダー統計
"to" : "213.79.2.30" 、 #統計
「lookup」 : 「velnet」
} 、
{ #VMテーブルの仮想マシン
「from」 : 「192.168.0.150」 、
「lookup」 : 「VM」
} 、
{ #VMテーブルの仮想マシン
「from」 : 「192.168.0.151」 、
「lookup」 : 「VM」
}
]

この例のルールはいくつかのプロパティを使用しますが、さらに適用できます。ipruleコマンドがサポートするすべてをカバーしようとしました。
cmd-コマンド。デフォルトではadd =ルールを追加します。
priority-指定されていない場合、 優先度は言及された順に1から自動的に番号付けされます。
fwmark-パケットラベル。
from-ソース;
to-宛先;
ルックアップ -テーブル。

今のルート:
ルート= [
{ #VPNクライアントの背後のネットワーク
「to」 : 「192.168.8.0」 、
"dev" : "tun0"
} 、
{ #1つのプロバイダーを介したVMテーブル
"to" : "default" 、
"via" : "5.6.7.8" 、
"dev" : "ppp0" 、
「テーブル」 : 「VM」
}
]

to-宛先;
経由 -どのゲートウェイを介して。
dev-どのインターフェースを介して;
テーブル -どのテーブル。

最後に、設定の最後の部分
ext_sure_ip = "8.8.8.8"
customcommands = "" "
「」
cmdfile = "/root/msr_ip.run"


ext_sure_ip-健全性を確認するためにpingにアドレスする外部インターフェイスの場合、現時点では何にも影響しません。
customcommands-すべての設定後に実行されるコマンド。
cmdfile-結果のスクリプトが書き込まれるファイル。

スクリプト本体


これで、スクリプト自体のみが存在し、これ以上の設定はなくなります。これについては、フラグメントのパーフィーラインがうれしく、レポートします。
#==この行の下にこれ以上構成設定はありません========================

輸入 OS
syslogの インポート
サブプロセスの インポート

syslog syslog ( "開始済み" )

フィールド= ( "dev" 、 "ip" 、 "gw" 、 "table" 、 "mark" 、 "works" 、 "state" 、 "role" 、 "type" 、 "weight" )
fout = open ( cmdfile、 'w' )
優先度= 1

#==システムのルールを追加
ルール=ルール+ [
{ "priority" : 100 、 "from" : "all" 、 "lookup" : "local" } 、
{ "priority" : 32766 、 "from" : "all" 、 "lookup" : "main" } 、
{ "priority" : 32767 、 "from" : "all" 、 "lookup" : "default" }
]


def isup ( dev ) :
x = サブプロセス 。 call ( [ "ifconfig" 、dev ] 、stdin = None 、stdout = open ( '/ dev / null' 、 'w' ) 、stderr = open ( '/ dev / null' 、 'w' ) 、shell = False )
if ( x == 0 ) :
r = 「アップ」
その他 :
r = 「ダウン」
リターン r

def works ( dev ) :
#グローバルext_sure_ip
x = サブプロセス 。 call ( [ "ping" 、 "-I" + dev、 "-c 3" 、 "-w 5" 、ext_sure_ip ] 、stdin = None 、stdout = open ( '/ dev / null' 、 'w' ) 、stderr = open ( '/ dev / null' 、 'w' ) 、shell = False )
if ( x == 0 ) :
r = True
その他 :
r = False
リターン r

def addmissingfields ( iface ) :
フィールドのfldの場合:
そうで ない 場合 ( ifaceのfld ) :
iface [ fld ] = なし

def openportcmd ( port ) :
r = "n $ IPTABLES -t filter -A INPUT"
ポート[ "sHost" ]の場合 :
r = r + "-s {0}" 。 形式 (ポート[ "sHost" ] )
ポート[ "proto" ]の場合 :
r = r + "-p {0}" 。 フォーマット ( port [ "proto" ] )
ポート[ "tPort" ]の場合 :
r = r + "--dport {0}" 。 形式 (ポート[ "tPort" ] )
r = r + "-j ACCEPT"
リターン r

def forwardportcmd ( port ) :
ポート[ "dHost" ]の場合 :
#allow $ IPTABLES -A FORWARD -p tcp --dport 3389 -j ACCEPT
r = "n $ IPTABLES -A FORWARD"
ポート[ "proto" ]の場合 :
r = r + "-p {0}" 。 フォーマット ( port [ "proto" ] )
ポート[ "nPort" ]の場合 :
r = r + "--dport {0}" 。 形式 (ポート[ "nPort" ] )
r = r + "-j ACCEPT"

#進む
r = r + "n $ IPTABLES -t nat -A PREROUTING"
ポート[ "sHost" ]の場合 :
r = r + "-s {0}" 。 形式 (ポート[ "sHost" ] )
ポート[ "proto" ]の場合 :
r = r + "-p {0}" 。 フォーマット ( port [ "proto" ] )
ポート[ "tPort" ]の場合 :
r = r + "--dport {0}" 。 形式 (ポート[ "tPort" ] )
r = r + "-j DNAT --to-destination {0}" 。 フォーマット ( port [ "dHost" ] )
ポート[ "nPort" ]の場合 :
r = r + ":{0}" 。 形式 (ポート[ "nPort" ] )
リターン r
その他 :
「」を 返す

def rulecmd (ルール) :
グローバル優先
優先度=優先度+ 1
r = 「ニップ規則」
if (規則の"cmd" ) および (規則[ "cmd" ] ) :
r = r + "{0}" 。 ルール [ "cmd" ]
その他 :
r = r + 「追加」

if (ルールの"優先度" ) および (ルール[ "優先度" ] ) :
r = r + "priority {0}" 。 形式 (ルール[ "優先度" ] )
その他 :
r = r + "priority {0}" 。 フォーマット (優先度)

if (ルールの"fwmark" ) および (ルール[ "fwmark" ] ) :
r = r + "fwmark {0} / {0}" 。 形式 (ルール[ "fwmark" ] )

if ( "from" in rule ) および ( rule [ "from" ] ) :
r = r + "{0}から" 。 形式 (ルール[ "from" ] )

if ( "to" in rule ) および ( rule [ "to" ] ) :
r = r + "to {0}" 。 形式 (ルール[ "to" ] )

if (ルールの"lookup" ) および (ルール[ "lookup" ] ) :
r = r + "lookup {0}" 。 形式 (ルール[ "lookup" ] )

リターン r

def routecmd ( route ) :
r = "nip route add"
if ( "to" in route ) および ( route [ "to" ] ) :
r = r + "{0}" 。 形式 ( route [ "to" ] )
#if(ルートの「ネットマスク」)および(ルート[「ネットマスク」]):
#r = r + "/ {0}"。format(route ["netmask"])
if ( "via" route ) および ( route [ "via" ] ) :
r = r + "via {0}" 。 形式 ( route [ "via" ] )
if ( "dev" in route ) および ( route [ "dev" ] ) :
r = r + "dev {0}" 。 形式 ( route [ "dev" ] )
if ( "table" in route ) および ( route [ "table" ] ) :
r = r + "テーブル{0}" 。 フォーマット ( route [ "table" ] )
リターン r

部分= "" "#!/ bin / sh

#==変数の設定===========================================
IPTABLES = / sbin / iptables
「」「
f。 書き込み (部分)


f。 書き込み ( "n#== interfaces:" )

ifacesのifaceの場合:
addmissingfields ( iface )

iface [ "state" ] = isup ( iface [ "dev" ] )

if ( iface [ "role" ] == "external" ) :
iface [ "works" ] = works ( iface [ "dev" ] )
descr = "{3} {0}は{1}で動作します= {2}" 。 形式 ( iface [ "dev" ] 、iface [ "state" ] 、iface [ "works" ] 、iface [ "role" ] )
f。 書き込み ( "n#" + descr )
syslog syslog ( descr )

部分= "" "
#==スクリプトの実行中に転送を許可しない=======================================
エコー0> / proc / sys / net / ipv4 / ip_forward
#==スクリプトの実行時にすべてのルールを削除=======================================
IPルールフラッシュ

#==既存のポリシーをすべて削除================================
$ IPTABLES -F
$ IPTABLES -t nat -F
$ IPTABLES -tマングル-F
$ IPTABLES -X
$ IPTABLES -Z

#==デフォルトポリシーの設定===================================
$ IPTABLES -P入力ドロップ
$ IPTABLES -P出力受け入れ
$ IPTABLES -Pフォワードドロップ

#==不良パケットの削除========================================
$ IPTABLES -t filter -A INPUT -m state --state INVALID -j DROP
$ IPTABLES -t filter -A OUTPUT -m state --state INVALID -j DROP
$ IPTABLES -t filter -A OUTPUT -m state --state INVALID -j DROP

#== SYNパケットのみが新しい接続を確立します================
$ IPTABLES -t filter -A INPUT -p tcp! --syn -m state --state NEW -j DROP
$ IPTABLES -tフィルター-A出力-p tcp! --syn -m state --state NEW -j DROP
$ IPTABLES -t filter -A FORWARD -p tcp! --syn -m state --state NEW -j DROP

#==安全なiface =========================================
$ IPTABLES -t filter -A FORWARD -i lo -j DROP
$ IPTABLES -t filter -A FORWARD -o lo -j DROP
$ IPTABLES -t filter -A OUTPUT -o lo -s 127.0.0.1/255.0.0.0 -j ACCEPT
$ IPTABLES -t filter -A INPUT -i lo -d 127.0.0.1/255.0.0.0 -j ACCEPT
$ IPTABLES -t filter -A OUTPUT -o lo -j DROP
$ IPTABLES -t filter -A INPUT -i lo -j DROP

「」「

f。 書き込み (部分)

f。 書き込み ( "" "

#==ポートを開いて転送する================================ "" " )
ポートインポートの場合:
f。 書き込み ( openportcmd ( port ) )
f。 書き込み ( forwardportcmd ( port ) )

f。 書き込み ( "" "

#==すべての場合:すべてのloc-locを許可、新しいloc 2 extを許可、extからnewをドロップ、extにマスカレード "" " )
ifacesのifaceの場合:
f。 write ( "n#==== for {0}" 。 format ( iface [ "dev" ] ) )
ifacesのofaceの場合:
if ( iface ! = oface ) :
if ( iface [ "role" ] == "local" ) および ( oface [ "role" ] == "local" ) :
f。 write ( "n $ IPTABLES -t filter -A FORWARD -i {0} -o {1} -j ACCEPT" 。format ( iface [ "dev" ] 、oface [ "dev" ] ) )
if ( iface [ "role" ] == "local" ) および ( oface [ "role" ] == "external" ) :
f。 write ( "n $ IPTABLES -t filter -A FORWARD -i {0} -o {1} -m state --state NEW -j ACCEPT"。format ( iface [ "dev" ] 、oface [ "dev" ] ) )

iface [ "role" ] == "local" :
action = "ACCEPT"
その他 :
アクション= 「ドロップ」
f。 write ( "n $ IPTABLES -t filter -A INPUT -i {0} -m state --state NEW -j {1}" 。 format ( iface [ "dev" ] 、action ) )

f。 書き込み ( "n $ IPTABLES -t nat -A POSTROUTING -o {0} -j MASQUERADE"。format ( iface [ "dev" ] ) )


f。 書き込み ( "" "

#==確立された転送を許可、他はポリシーによってドロップされます
$ IPTABLES -t filter -A FORWARD -m state --state ESTABLISHED、RELATED -j ACCEPT
$ IPTABLES -t filter -A INPUT -m state --state ESTABLISHED、RELATED -j ACCEPT

「」「」 )


f。 書き込み ( "" "
#==一部のifacesセットテーブル、マークとルール====================================== ============== "" " )
ifacesのifaceの場合:

iface [ "table" ] および iface [ "gw" ] および iface [ "table" ] :
f。 書き込み ( 「{0} dev {1}テーブル{2}を介したデフォルトのnipルート追加」 フォーマット ( iface [ "gw" ] 、iface [ "dev" ] 、iface [ "table" ] ) )

iface [ "マーク" ] :
f。 書き込み ( rulecmd ( {
"fwmark" :iface [ "マーク" ] 、
"lookup" :iface [ "テーブル" ]
} ) )


f。 書き込み ( "" "

#== ifaceを介して回答を送信する必要があります================================== "" " )
#ifacesのifaceの場合:
#iface ["マーク"]:
#fout.write( "n $ IPTABLES -t mangle -A INPUT -i {0} -j CONNMARK --set-mark {1}"。format(iface ["dev"]、iface ["mark"]))
#fout.write( "n $ IPTABLES -t mangle -A OUTPUT -j CONNMARK --restore-markn")
ifacesのifaceの場合:
iface [ "table" ] および iface [ "gw" ] :
f。 書き込み ( rulecmd ( {
「from」 :iface [ "gw" ] 、
"lookup" :iface [ "テーブル" ]
} ) )

f。 書き込み ( "" "

#==ルールのリストからのルール================================== "" " )
ルールのルールの場合:
f。 書き込み ( rulecmd ( rule ) )

f。 書き込み ( "" "

#==ルートのリストからのルート================================== "" " )
ルート内のルートの場合:
f。 書き込み ( routecmd ( route ) )

f。 書き込み ( "" "

#==外部ifacesインターリーブ(すべてのUP ext間)=================================== "" " )
部分= 「nip route replace default scope global」
ifacesのifaceの場合:
iface [ "dev" ] および iface [ "gw" ] および iface [ "weight" ] および ( iface [ "role" ] == "external" ) および ( iface [ "state" ] == "up" ) :
portion = portion + "nexthop via {0} dev {1} weight {2}" 。 形式 ( iface [ "gw" ] 、iface [ "dev" ] 、iface [ "weight" ] )
f。 書き込み (部分)

f。 書き込み ( "" "

#==転送を許可============================================ =============================
エコー1> / proc / sys / net / ipv4 / ip_forward
「」「」 )

f。 書き込み ( "" "

#==いくつかの手作りのカスタムコマンド========================================== =====================
{0}
"" " 。format ( customcommands ) )


f。 閉じる ( )

syslog syslog ( "完了" )
syslog syslog ( "スクリプトが開始されました" )
x = サブプロセス 。 call ( [ "/ bin / sh" 、 "{0}" 。 format ( cmdfile ) ] 、stdin = None 、stdout = open ( '/ dev / null' 、 'w' ) 、stderr = open ( '/ dev / null ' 、 ' w ' ) 、shell = False )
syslog syslog ( "スクリプトは結果{0}で終了しました"。format ( x ) )



打ち上げ


現在使用しているオプションの1つは、インターフェイスを変更するときにスクリプトを呼び出すことです。 このために、呼び出しスクリプトが書かれています:
 
  ルート@ゲート:/ルート#cat ./msr_on_if_changed  
  #!/ bin / sh 
  / usr / bin / python /root/msr_ip.py 
  出口0 
 

スクリプトへのリンクは、ネットワークインターフェイス構成ディレクトリにインストールされます。 主なことは、名前が拡張子なしになることです。そうしないと、初期化システムによってリンクが無視されます。
 ln -s /root/msr_ip.py / etc / network / if-down / msr_ip
 ln -s /root/msr_ip.py / etc / network / if-up / msr_ip
 ln -s /root/msr_ip.py /etc/ppp/ip-up.d/msr_ip
 ln -s /root/msr_ip.py /etc/ppp/ip-down.d/msr_ip

合計


このスクリプトは3か月間実行されており、これまでのところ、その障害による障害はありませんでした。

Source: https://habr.com/ru/post/J138705/


All Articles