Linux Gazette 2月投稿記事抜粋
02/04/2004 - 08:35 Your Public IP Address and ssh by Willy Smith
02/07/2004 - 05:42 Newbie guide for FTP install of SuSe 9.0 by Dave Crouse
02/14/2004 - 16:43 Using GnuPG, Part I by Sandro Mangovski
02/17/2004 - 14:37 Debugging Tools for C on Linux Platform by Nikhil Bhargava
02/18/2004 - 08:46 UDP Sockets-based Client Server Programs by Nikhil Bhargava
02/28/2004 - 05:53 Network Protocol Stack & TCP hacking by shyamjith
Willy Smith 提出2004年2月4日
インターネットユーザの多くは、自分のコンピュータが持つIPの殆どに公開IPアドレスがあることを知らない。この記事は、基本的概念の概要を述べてsshを公開アドレスで用いる方法を述べる。
インターネットに接続すると自分のコンピュータに対するアドレスを外の世界に示すのは、避け難い事実だ。殆どの場合、規律は保たれていると思うが、ハッカーに遭った人達は、それは幻想に過ぎないと云う。私も、余り良く知らなかったためテルネットボートを開いたまま走らせてサーバ/ファイアウォールに侵入されたことがある。ルーマニアの誰かが私のコンピュータに侵入して、メガバイトものファイルをインストールした。幸い、それが起こった時コンソールの前にいたが、侵入者が新規優先ユーザを作り、ゲームサーバであることが明らかな巨大なファイルをアプロードしてインストールするのを呆然と眺めるだけだった。システムをシャットダウンしたが、私より詳しい人にシステムのクリーンアップ方法を聞いたとき、一旦起こってしまうと、完全にクリーンアップするのは難しいので、Linuxをインストール仕直すほかないと云われた。幸い、データは喪失しなかったが、その時以来コンピュータのセキュリティに神経質になった。この場合は、SuSEの新バージョンをインストールして必要な機能を満足しつつもファイアウォールが出来る限り堅固であるのを確認するのに一寸手間を掛けた。
インターネットに接続するとき、その接続には臨時公開IPアドレスが割当られる。私はISDENモデモを持っており、これがアクセス番号をダイアルする。ダイアラのトップには統計ウインドウがあり「ローカルIPアドレス」と「リモートIPアドレス」が示されている。ここコスタリカでの私のプロバイダ(ICE)用に「208.xxx.yyy.zzz」が常に示されている。これらIPアドレスは両方とも、インターネットを通じて世界中から見ることの出来る公開アドレスである。ローカルアドレスは、接続折衝中に私のISDNモデモに割り当てられるアドレスである。リモートアドレスは私のモデモが接続する電話線の向こう側の交換局にある装置のアドレスである。リモートアドレスには格別の興味はないが、ローカルアドレスは、外の世界から自分のコンピュータにアクセスするため関心がある。
さて、接続の種類によってはこれが出来ない。例えば(このサイトでも働いている) Mitch にはケーブルモデモがある。このケーブルモデモにはIPがあるが、これは全くケーブルモデモ会社のファイアウォールの後にある非公開ネットワーク上にある。これはもっと安全であろうと思うだろうが、このローカル・ネットワーク内のユーザがこのコンピュータに対するアクセスを持っているのに注意するのも面白い。事実、Mitchもまた同一のゲームサーバに侵入されたが、これは自分のいるローカルから来たものだった。
自分の公開IPアドレスが外界からアクセス出来るが否かを点検するには、無料オンライン・セキュリティ・スキャンサービスを利用することが出来る。私が使っているのは Sygate Security Scanだが、Googleサーチなどでも出来る。Quick Scanを使うと、ポートの状態を見ることが出来る。私のポートはssh以外にはブロックしてある。Security Scanサイトにいる限り、ポートを点検して保護されているか否かを点検しなければならない。最もいけないのは、Sambaを走らせてポート139をインターネットに開くことだ。この場合、世界中の人に自分のファイルシステムへのアクセスを与えることになるので、簡単に侵入される。
ssh(22)が使っているポートが開いていないときは、開く必要がある。ddhデモンを走らせる必要もある。私はSuSEを走らせているので、ファイアウォール構成に入り、sshを有効にし、またsshをランレベル・エディタで有効にするのは容易い。別のLinuxでは、これを行う方法を見付けなければならない。これを見た誰かが投稿して呉れるだろう。
sshの働きを少々理解するのは大切だ。telnetに慣れている人には、基本機能が良く似ている。これは、目標ホストシステムに対するコマンド行アクセスを与えるプログラムだ。相違は、telnetにログインするとユーザのパスワードが平文でインターネットに送られる。これはセキュリティの維持には良くない。駐車して買い物に行くとき、車のキイと札の着いたキイをバックミラーに引っ掛けて置くようなものだ。sshを使うには認証のレベルもある。リモートホストに始めてログインするとき、sshはホストが未知のキイを持っているとの警告が出て、「yes」とタイプしてキイを検証することを要求する。誰かがこのホストを騙そうとすると、キイが変わってsshは変更を通知してくれる。
コンピュータ上でsshが走りインターネットに接続されると、インターネットに接続された遠隔地から自分のコンピュータにアクセスすることが出来る。これは、前の記事で記述したKDE sftp:// プロトコルの使用を含む。一言付け加えると、Mitchはインターネットに接続されたコンピュータの後にあるコンピュータの一つにsshがアクセスする方法を記述する。これを付け加えるのは、これがLinux Gazetteの記事になるからだ。
sshはデータの暗号化圧縮転送を提供するので、暗号化されていないプロトコルとサービスを使って、インターネット経由のデータ移植をsshにさせるのが安全な方法だ。一つのサービス/プロトコルを別のものの中に入れるこの処理は、トンネリングと呼ばれる。ssh自体をローカルネットワーク上の別のコンピュータにトンネルする方法に関する Mitchの注釈を示す。
●自分のシステムにプライベートIPアドレスは一つだけしかないが、それがまた公開IPアドレスをも持つシステムに対する接続を有するとき、公開システムとsshとを自分のゲートウエイとして働くよう使用することにより、この機構を経由してプライベートシステムにアクセスすることが出来る。それを行うには:
1.ローカルホスト用に新しい別名を自分の /etc/hostsに追加する。私の場合の別名はprivateboxだ。
127.0.0.1 localhost mybox privatebox
2.ここで、シェルをスタートしてsshを走らせ、自分のローカルシステム上のポートをプライベートシステム上のポートに送る:
ssh -L 1092:192.168.1.99:22 -N publicbox.com
○オプション-Lポート1:ホストポート2は、sshに対し、ローカルシステム上のポート1を、ゲートウエイとして実際にそれが接続されるローカルシステムを使っている規定のホスト上のポート2に送ること、を命じる。。
■1092は自分のローカルシステム上のポート番号である。ポート1092は任意で、1024より大きい任意の値のうち最大を用いる。「bind: Address already in use(結合:アドレスは使用中)」との警告をsshが出したら別のポートを試すこと。
■192.168.1.99 は、アクセスしたいプライベートシステムの IPアドレスである。
■22は、プライベートシステム上のポート番号である。ポート22は、sshが使う標準ポートなので、これは変えないこと。
○オプション-Nは、sshに対し、ゲートウエイとして働くことを命じる。送り出すポートだけが必要なので、シェルは必要でない。
○publicbox.comは、ゲートウエイとして働く公開システムである。sshが実際に接続するシステムは、これである。
実際に起こる事柄は:sshがpublicbox.com、公開システム、に通常のsshの方法で接続する。同時に、これはローカルシステム上のポート1092を聴取する。ポート1092で聞くこと全部に特別なマークを付け、通常ssh接続を通じて公開システムに送る。公開システム上では、ssjが 192.168.1.99でプライベートに(別のネットワーク・インターフェイスを経由して)接続し、特別マークのあるもの全部をプライベートシステム上のポート22に送る。言い換えると、これは公開システムを経由してローカルシステムとプライベートシステムとの間に通信路を作る。ポート22は通常sshポートなので、これでローカルシステムからプライベートシステムまでの通信路が出来上がるので、 sftp:// protocolがこれを使うことが出来る
3.ここで好みのKDEアプリケーションをスタートして、ファイルを開くダイアログに入り、sftp://privatebox:1092と入力する。これは、ポート1092でprivateboxに接続しようとする。上のステップ1でprivateboxを別名にしたので、これがローカルシステムをポート1092に接続する。上のステップ2で、sshがローカルシステム上のポート1092を聴取し始め、マークして通常ssh接続を通してポート22のプライベートシステムに送る。privateboxでは、sshがポート22の上の通信を見て、それが公開システム経由でゲートウエイされていることには気付かないで普通に対応する。
これで面白いことが起こることに注意。例えば、現在の臨時IPアドレスを使って友人のホームを訪問し、自分のシステムとファイルを遣り取りすることが出来る。、また遠隔から自分のe-メールや任意の数のその他のサービスにアクセスすることが出来る。昨日 Mitchを呼び出してこれを試した。この技術を使って私のプライベート・ネットワーク上の、どのコンピュータにもアクセスすることが出来た。未だ解明出来ない傷害にぶつかった。殆どのPCはSuSE 8.2を走らせているのでsshもsftp:// も上手く働くが、MitchはSuSE 9.0を走らせる私のメインPCにはsftp:// を使ってファイルをブラウズずることが出来なかった。
sshを別のアプリケーションのトンネルに用いることが出来る。例えば、自分のメールを一般的なポストカードより一層安全にしたいときは、tunneling POP over ssh (PDF, 274k)と云う指導書がある。POP e-メールもまた平分で送られるので、そのe-メールデータが取る通信路に対するアクセスを持つ者は誰でもそれを読むことが出来のを想起されたい。
私がLinuxをデスクトップで使い始めて1年も経っていないが、それでもWindowsシステムを使っていたときは縛られていたと思う。sshをログインに使う能力と私の(誰でも自分の)コンピュータを遠隔から使う能力は極めて有用だ。それが無いと困るようになった。sshを使うため少々の勉強をする価値はある。習ってしまえば、パスワードを外に出さないだけで日常の役に立つ。
Copyright © 1996-2003 Specialized Systems Consultants, Inc.
Linux Gazette は Specialized Systems Consultants, Inc.の商標です。
SuSe 9.0のFTPインストールに関する初心者手引き
Crouse提出:2004年2月7日 - 05:42
これはSuSe 9.0のFTPインストールに関する初心者手引きだ。全部を読むと、手順が分かり、インストールを終えるのに必要なデータた入手出来る。
SuSeは無料isoダウンロード版を提供していないので、この手引きをSuSe 9.0ネット・インストール(ftpインストール)での方法を述べる。これは無料だがサポートはない。手引きも提供しているが、十分ではない。そこで段階毎の手引きを書く。
SuSe からのミラーを開いたら、boot.iso のあるディレクトリを見出してboot.iso をダウンロードする。ファイルサイズは21.6MBなので、大した時間は掛からない。
boot iso をダウンロードしたら、イメージとしてブランクのCDRに焼き付ける。
次に、そのディスクコンピュータに入れて、ブートし直す。歓迎メッセージが出て選択画面に進む。Installationを選ぶ。
Installationを選んで --- enter キイを押す。.
{Loading Linux Kernel...............} と出て次の画面に進む。.
MAIN MENU 画面が出る。幾つかの選択肢がある。
先ずSettings を選ぶ。Language の選択を間違えないこと。次いで KERNEL MODULES を選び、Load network card modulesを選ぶ。ネットワーク・カードを選んで挿入する。
別のモジュールを挿入する必要があれば、ここで行う。終わったら、メインメニューに戻って START INSTALLATIONを選ぶ。次にsource medium (NETWORK)を選び、FTPを選ぶ。次に、カードがインターネットにアクセス出来るようにするため、AUTO CONFIG VIA DHCPを選ぶか又は、人手で行う。
次が苦労だ。FTPサーバの IP ADDRESS に入らなければならない。幾つかの方法があるが、Linux上でDIGコマンドを使ってIPアドレスがを見つけた。
使っているFTPサーバが何であろうと、IPアドレスを見出すにはターミナルでdigコマンドを使わなければならない。私はftp://mirror.mcs.anl.gov/pub/suse/FTPサーバを使ったので、digコマンド:dig mirror.mcs.anl.govを使ってIPアドレス140.221.9.138一つが戻った。IPアドレスを要求するボックスにこの数字を入れる。enterを押すと、username とpasswordを使うかどうか聞いて来るのでnoと答える。Http proxyを使うかどうかもNOだ。
ここまで正く進むと"trying to connect to ftp server"と言って来て、接続されると "Please enter the directory on the server"と言って来る。
ftp://mirror.mcs.anl.gov/pub/suse/ ftp サーバについて正しい入力は: pub/suse/i386/current/だ。
小さい画面が出て "Loading data into ramdisk (46760 kB)”と言う。接続されて、インストールの難しい部分は終わった!!
その後、データがRAMディスクにダウンロードされ、挨拶の言葉が出る。
ここで先ず、もう一度 languageを選び直す。Yastがハードウエアを検出してこれらのdrivers/modulesをロードしたいか聞いて来る。検出ハードウエアにyesと言って悪いとは思えないのでyesを選ぶ。その後のインストレーションは一直線で容易だ。Yastインストーラは素晴らしいパーティション作成ツールだ。
最小限、以下のパーティションは必要だ。
/boot 小型 50 mb
ramが沢山あるのでない限り、500 mb と交換する
/root 2+ gigs 最低
/home ハードディスクの残り、又は別のパーティション又はルートの専用とする
注記: SuSe auto-partition をさせることも出来る。良いか否か不明。
ネット・インストールには、速い接続でも少し時間が掛かる。サーバ全部が走っていて、殆どの時間、全能力で働いた。私の場合3時間余り掛かった。
インストールを終えて、ルートパスワード、ユーザを設定し、グラフィックカードを設置したら、全部終わりだ。
この記事が役だったことを願う。
主ダウンロードペイジ: http://www.suse.com/us/private/download/suse_linux/index.html
SuSe ミラーペイジ:http://www.suse.com/us/private/download/ftp/int_mirrors.html
インストレーション手引き:ftp://ftp.suse.com/pub/suse/i386/9.0/README.FTP
本記事の最新版: http://www.usalug.org/phpBB2/viewtopic.php?p=8161
Sandro Mangovski提出:2004年2月14日
GnuPGの利用
今日では、通信線が昔の時間と距離との限界を突き破った。どんな遠くにいる人ともリアルタイムで話すことが出来る。同じ利便が、問題も生じる。第一に、相手を100%確実に確認することが出来ない。第二に、間に通信を傍受する第三者がいても分からない。幸い、公開キイ暗号と呼ばれるものが発明された。
システム全体の説明は到底出来ないので、何かを読んで欲しい。
GNU Privacy Guardをインストールする必要がある。これは、我々の使う PGP 互換ソフトウエア・パケージだ。Linuxディストリビューションに付いて来るパケージを使っても良いし、ソースを
http://www.gnupg.org/ からダウンロードしてコンパイルしても良い。簡単なのでここでは述べない。.
終わったら、働かせることが出来る。先ずすることは、自分の公開/秘密キイのペアをつくることだ。次のコマンドを用いておこなう:
gpg --gen-key
ここで、使用したいアルゴリズムを聞かれる。(1)でも(3)でも同じなので、自由に選ぶ。次のステップは、キイの大きさの決定だ。規定値で推奨値は1024だ。その後で、自分のキイ・ペアの有効期間を満たす必要がある。それを終わったら、自分のアイデンティティパスフレーズを入力する。パスフレーズは、暗号化、メッセージ又は他人キイのサインの度に入力する必要があるので、覚えていないといけない。数字と特殊文字のある無作為の文字列でなければならない(89jdsh,eH:@ke98など)。これらの文字列ならら破れないからだ。自分のキイ・ペアキイリングに記憶したとしよう。
キイ・ペアが出来たら、廃止証明書を書く必要がある。パスフレーズやキイを忘れた時、補完するのに用いる。これは次を用いておこなう:
gpg --output revoke.asc --gen-revoke mykey
引数 mykey は、主キイ・ペアキイ・のキイID又はユーザIDの任意の部分のいずれかで、自分のキイ・ペアを識別するスペシファイアでなければならない。この証明書を厳重に注意して記憶しなければならない。これを入手する誰かが、これを使ってキイサーバ・ネットワークからキイを無効にするからである。
自分のキイを他の人との通信に使いたいときは、相手にそれを示さなければならない。そのためには、キイをファイルにエキスポートしなければならない。ファイルは規定値でバイナリフォーマットであるが、キイはASXIIフォーマットでエキスポートする規則になっている。方法は次の通り:
gpg --export file.gpg --armor --export mykey
--armorオプションは 、キイをASCIIフォーマットエキスポートするので、キイをバイナリにしたいときは--armor を外す。秘密キイのエキスポートは--export-private-key オプションを用いておこなう。これには勿論セキュリティのリスクがあるので、エキスポートする秘密ファイルには誰もアクセスしないようにしなければならない。キイをキイリングにインポートするには gpg --import key-file.gpg を使い、キリングの中のキイをリストするには gpg --list-keysを用いる。
ここで、キイの編集について少し学ぶ。gpg --edit-key コマンドでキイ編集メニューに入る。キイに何が出来るかはhelpとタイプする。殆どのオプションは自明で、説明の必要はないが、最も重要なものに触れる。最初のコマンドは、fprで、次のような出力をする:
Command> fpr pub 1024D/670DE738 2004-02-14 Sandro Mangovski <sandro@somewhere.net> Fingerprint: DE52 6330 D036 B9F2 E1A2 CD7C 40C0 7DF7 670D E738
世界中のあらゆるキイには独特の指紋があり、これを用いてキイを検証することが出来る。相手を電話に呼び出して誰かのキイを検証しようとすると、他人には公開キイ全体を読取るのが、君には点検するのが難しい。だから指紋なのだ。相手は指紋で君を読取り、君が持っているキイと同じなら、正しいキイを持っていると確信することが出来る。
Command> check uid Sandro Mangovski <sandro@somewhere.net> sig! 670DE738 2004-02-14 [self-signature]
このコマンドは、君の持っているキイのサインをリストする。キイは、相手方でチェックしなくとも検証することが出来る。それがサインだ。キイにサインする人は誰でも、そのキイは、本当に自分のものだと宣言する人のものであることを検証する。GnuPGでは、それに個人的にサインするか、又は完全に信用するキイ一つでサインするか余分に三つのキイを信用するとき、そのキイは有効であるとみなす。もう一つ条件があって、それは、或るキイに導く署名キイが君自身のキイに戻るパスががか、5ステップ以下であることだ。キンにはキイ編集メニューの sign コマンドを用いてキイにサインすることが出来る。
終わりの方で「キイを信用」と言う言葉を使った。キイ編集メニューで trust コマンドを用いると信用のレベルを変更することが出来る。このメニューには、二次キイの追加、署名の撤回、ユーザIDの追加と撤回などキイ管理のための能力があるので、これらオプション全部を試されると良い。
キイ管理の基本が分かったところで、自分のキイをインターネットに公開し、その公開キイを使って暗号化文書を送りたい人に使って貰うことが出来る。キイは、インターネット上で、所謂る公開キイサーバに記憶される。これは殆どの場合、リンクされているので、どのサーバに自分のキイをアップロードするかは重要ではない。自分のキイを自分か又は他のの誰かがサーバにアップロードすると(誰かが君のキイに署名するか、自分でキイの変更をする度に起こる筈)、旧版は上書きされないで、新版と合併される。署名や二次キイを削除するだけではいけないのはこの理由だ。これらを削除する代わりに、無効にすると良い。無効がサーバ上のキイに合併されるので、そのキイに署名がないことは誰にも分かる。君が誰かのキイに署名するときは、既に述べたように、それをキイサーバ・ネットワークにアップロードしなければならない。君の署名がそのキイに合併されて、キイの検証に役立ち、それをすることによりセキュリティと信用を増強し、それはシステムの効率と安全な使用に重要だからだ。キイをPKAに登録する方法を示す:
gpg --keyserver certserver.pgp.com --send-key mykey
gpg --keyserver certserver.pgp.com --recv-key 670DE738 コマンドを用いて、キイサーバから一つのキイを取り込む。--recv-key オプションには --send-key オプションと異なる引数があることに注意。最初のオプションはキイにつながるユーザIDの一部を使用するが、キイを取り込むときは、キイIDを知っている必要がある。
キイ管理の基本が分かったところで、キイを使って何か役立つことをしよう。先ず、簡単な仕事として、ファイルを暗号化し解読する方法を学習しよう。
gpg --output file.out --encrypt --recipient strpic@spider.irb.hr file.doc
このコマンドは、file.docを暗号化して出力を file.outに記憶する。--recipient オプションは、受領者毎に使用しなければならない。またこれは、ファイルの暗号化に用いる公開キイを規定する引数を取る。ファイル解読をおこなうコマンドは:
gpg --output file.doc --decrypt file.gpg
GnuPG には文書署名(document signing)と言う重要な機能がある。デジタル署名が文書を認証し時間を記録する。後で文書が修正されると、署名の検証が出来なくなる。デジタル署名は、手書き署名と同じ目的の他に、改竄防止の役にも立つ。署名は秘密キイを用いて行うが、検証は公開キイを用いて行うことに注意。文書の署名には三つの方法があり、その各々がパスフレーズを必要とする。
1.) Plain(平文)署名
gpg --output file.sig --sign doc
これの出力はバイナリ・フォーマットで、文書は署名の前に圧縮される。
gpg --output doc --decrypt doc.sig コマンドが、メッセージを解読して署名を検証する。署名が正当であるとき、以下と同様の出力が生じる:
is good: gpg: Signature made Sub 14 Vel 2004 13:38:30 CET using DSA key ID 670DE738 gpg: Good signature from "Sandro Mangovski <sandro - at - mosor.net>"
2.) Clear(透明) 署名
文書に透明署名すると、メッセージが署名に包まれ、これは圧縮されない。これは通常e-メール・メッセージ及びusenet投書に署名するとき用いられる。ほとんどのメール・ユー座・エージェントは、この機能を埋め込んでいるので、コマンド行からgpgを使う必要はない。クリア署名は、自分のキイリングに自分のキイを持っていないため、先ずメッセージを読んでいとき次に信頼性をたしかめるとき有用である。
gpg --clearsign file コマンドで文書にクリア署名をし、gpg --verify doc.asc で署名を検証する。
3.) Detached(分離)署名
この方法での署名には利点がある。ファイルは原型のままで署名は分離されているので、他人が署名ファイルから復元することは出来ない。署名の検証には文書と分離署名が必要である。これらのコマンドには仕掛けがある: gpg --output file.sig --detach-sig file で文書に署名しgpg --verify file.sig file でそれを検証する。
これで終わりだ。これで GnuPG を使えるが、キイの記憶と君のwebの信用を保つなどのため幾つかのセキュリティ対策がある。これらは大変重要なので、別のパートで述べる。GPGを使い、常にセキュリティに心を配られたい。GnuPGドキュメントには、この記事より詳しい説明があるので読まれたい。
Nikhil Bhargava提出:, 02/17/2004年2月17日 - 14:37
この記事はLinuxプラットホーム上のCのデバッグ用ツールについて述べる。ほとんどのツールは、主なプラットホーム上で無料で利用することが出来、広範なユーザサポートがある。ツールは、コードの静的解析と同時に、コードの動的評価を助ける。
ここに掲げたツールは、筆者の提案であることに注意されたい。このリストが標準ではない。開発するアプリケーションの性質、範囲及び詳細に左右されて、変更しなければならない。
デバック用ツール
Dmalloc(debug memory allocation)ライブラリは、システムのmalloc, realloc, calloc, freeその他メモリ管理ルーチンの代替として特に設計された小粒だが、ランタイムで構成出来る強力なデバック機能を備えている。コンパイル中に変更を行って、バイナリではランタイム変更を追加しない。これらの機能には、メモリリーク追跡、フェンス-ポスト書込検出、ファイル/行番号報告、統計の一般記録などが含まれる。ライブラリは、少なくとも以下のOSでうまく働いているので、それなりに移植可能である:AIX, BSD/OS, DG/UX, Free/Net/OpenBSD, GNU/Hurd, HPUX, Irix, Linux, MS-DOG, NeXT, OSF, SCO, Solaris, SunOS, Ultrix, Unixware, Windoze, Cray T3E上のUnicos 。これには、プログラム用の完全なサポート POSIX スレッドのデバッグがある。
パケージには、ライブラリ、コンフィギュレーション・スクリプト、デバッグ・ユティリティ・アプリケーション及びドキュメンテーションが含まれる。
Valgrind は、x86-Linuxプログラムのデバッグとプロファイル作成のためのGPL分散システムである。x86バイナリの作用は他のバイナリと似ているので、これはx86以外のプラットホーム用のプログラムにも役立つ。Valgrindに付属のツールは、メモリ管理とスレッドのバグの多くを自動的に検出して、バグ探しの時間とイライラを無くし、プログラムを安定にする。これは、徹底的に詳細なプロファイル作成をサポートしてプログラムの速度を向上させる。
Valgrind ディストリビューションには、メモリエラー・デテクタ二つ、スレッドエラー・デテクタ、キャッシュ・プロファイラの、四つのツールが含まれる。
Electric Fence は、Cプログラム作成とデバッグに使用することの出来るフリーウエア・ライブラリである。コンパイル時にリンクすることが出来て、存在しないメモリの解放などあり得る問題に付いて警告を与える。基本的にはメモリ・プロファイル作成ツールである、しかし、現在ではHP-Unixプラットホームでのみ利用することが出来る。(確信はないが)
これは、Red Hat, Slackware, Debian など、フリーウエアLinuxディストリビューションと一緒にフリーウエア・サポート・パケージとして来るGNUデバッガである。C, C++, Perl など多数の言語の完全サポートを有する。これら言語のバイナリを、単一ステップ、多重ステップ、完全ランのモードでデバッグするのに役立つ。ブレーク・ポイントと値の追跡の設定をも備えている。
スタブ・テスト、ファンクションの流れ点検、束縛点検に有用である。さらにこれは、Linux及びUnixプラットホームの全種類で容易に利用することが出来るので、ユーザ社会で広くサポートされる。
Insight は、Red Hat, Inc とCygnus Solutions (今は Red Hatの一部)が Tcl/Tk 書いたGNUデバッガ、GCBに対するグラフィック・ユーザ・インターフェイスである。Insightは、GDBが備える全ての特徴とともに、従来のコマンドベースのインターフェイスに代わる、グラフィック・デバッグ・インターフェイスを提供する。
MemProf は、フリーウエアの、メモリプロファイル作成及びメモリリーク検出ツールであって、普通のLinuxディストリビューションに付録として付いて来る。プログラム中の各ファンクションによりメモリが幾ら割り当てられるかに関するプロファイルを作る。メモリをスキャンして、割り当てられてはいるが最早参照されていないブロック(デッドコード)を見出す。
MemProf は、ライブラリを予めロードして、Cライブラリのメモリ割当ファンクションを上書きすることにより働くので、プログラムのコンパイル仕直しを必要としない。他の同様のツールを超えてMemProf が持っている利点は、GUIフロントエンドがあることと、比較的使い易いことである。
クライアント/サーバ・プログラム
Nikhil Bhargava提出:2004年2月18日 - 08:46
この記事は、簡単なUDPクライアント/サーバ・システムをLinux又はUnixプラットホーム用にCで書く方法を説明する。UDPソケットを用いるクライアント/サーバ・アプリケーション書くのは極めて易しいと思われているが、大切なステップを抜かしたりして、デバッグに大変な時間を掛ける事がある。沢山のマニュアルを渉猟するのでなければ、ソケットAPIの詳細を急速に覚えるのは難しい。そこで、ここでは、UDPクライアント/サーバ・プログラムの基準を示す。
モジュールは三つのファイルから構成される。ヘッダファイルとソースファイル二つだ。共通ヘッダファイルInclude.hは、プログラムで使用する標準ヘッダ、データ型、ユーザ型構造体を含む。ソースファイルclient.c は、UDPクライアント含み、ファイル server.c は、UDPサーバを含む。GTPUプロトコル(UMTSネットワーク)用に保留されるサーバ(2152)用に固定ポートを選んだ。さらに、クライアントとサーバのIPアドレスは、私のワークステーションのIPアドレスなので変更する必要がある。
保証:
この記事に示すコードは、Red Hat Linux 8.0 (kernel 2.4.22)で働くことをテストしてある。Linux /Unixシステムでも働く筈だが、別のシステムではヘッダファイルを別のディレクトリに置かなければならないかも知れない。実行するには、先ずServer 次に Clientを入らせる。
ソースコードとその説明 :
ソースコード全体の構成は次の通りである:ヘッダファイルInclude.hには、包括的に必要なヘッダと同時にネットワーク特有のファンクション、標準データ型、ネットワーク固有パラメータ及びクライアントとサーバの間の交換に必要なメッセージ構造体が含まれる。
クライアントは、リクエストメッセージに、クライアントとしてのセンダレイヤ、リクエストとしてのメッセージ型及び一連番号を付けて、予め定めるIPアドレスと固定ポート番号とともに、サーバに対して送る。そして応答を待つ。UDPベースなので、先立つ接続は設定されていない。
サーバはクライアントからの上りリクエストを待つ。受け取ると、応答メッセージに、サーバとしてのセンダレイヤ、応答としてのメッセージ型、リクエストメッセージから受け取る一連番号を付けて、クライアントに対して送る。ここでも、UDPベースなので、データ転送に先立つ接続は設定されていない。
Include.h
1. #include <stdio.h>
2. #include <stdlib.h>
3. #include <string.h>
4. #include <assert.h>
5. #include <errno.h>
6. #include <sys/socket.h>
7. #include <sys/types.h>
8. #include <netinet/in.h>
9. #include <arpa/inet.h>
10. #define S8 char
11. #define U8 unsigned char
12. #define S16 short int
13. #define U16 unsigned short int
14. #define S32 int
15. #define U32 unsigned int
16. #define S64 long long int
17. #define U64 unsigned long long int
18. #define DATA_PORT 2152
19. #define CLIENTIP "196.1.105.18"
20. #define SERVERIP "196.1.105.36"
21. typedef enum sender{CLIENT=1, SERVER=2} SenderLayer_e;
22. typedef enum primitive{REQUEST=3, RESPONSE=4} Primitive_e;
23. typedef struct pdu
24. {
25. SenderLayer_e SenderLayerid;
26. Primitive_e Primitiveid;
27. U32 number;
28. }PDU_t;
client.c
1. int main()
2. {
3. S32 k,j;
4. S32 sockfd;
5. PDU_t Pdu;
6. struct sockaddr_in Source, Target;
7. struct in_addr a;
8. bzero ((U8*)&Source,sizeof(Source));
9. Source.sin_family=AF_INET;
10. Source.sin_addr.s_addr=htonl(INADDR_ANY);
11. Source.sin_port=htons(0);
12. if((sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))==-1)
13. {
14. printf ("\n Socket for data msgs cannot be created\n");
15. exit(-1);
16. }
17. /* Now we need to bind it to the os underlying queues */
18. if(bind(sockfd,(struct sockaddr*)&Source,sizeof(Source))==-1)
19. {
20. perror("\n Data socket cannot be binded to OS\n");
21. exit(-1);
22. }
23. bzero((U8*)&Target,sizeof(Target));
24. Target.sin_family=AF_INET;
25. Target.sin_port=htons(DATA_PORT);
26. s_addr=Target.sin_addr.s_addr=inet_addr(SERVERIP);
28. Pdu.SenderLayerid=CLIENT;
29. Pdu.Primitiveid=REQUEST;
30. Pdu.number=1;
32. printf("\n...start sendto....\n");
33. j=sendto(sockfd,(void*)&Pdu,sizeof(PDU_t),0,(struct sockaddr*)&Target, sizeof(Target));
34. printf("\n\n packet send to IP %s at port %d...",inet_ntoa(a),ntohs(Target.sin_port));
35. printf("\n...end sendto....\n");
37. printf("\n...start recvfrom....\n");
38. bzero ((U8*)&Source,sizeof(Source));
39. k=sizeof(Source);
40. j=recvfrom(sockfd,(void*)&Pdu,sizeof(PDU_t),0,(struct sockaddr*)&Source,&k);
41. s_addr=((Source.sin_addr.s_addr));
42. printf ("Received from %s at port %d\n",inet_ntoa(a),ntohs((Source.sin_port)));
43. printf("\n Sender Layer %d\n",((PDU_t)Pdu).SenderLayerid);
44. printf("\n Primitive %d\n",((PDU_t)Pdu).Primitiveid);
45. printf("\n Pdu number %d\n",((PDU_t)Pdu).number);
46. printf("\n...end recvfrom()....\n");
47. close(sockfd);
48. return 0;
49. }
クライアント内部
・1 行目: client プログラムの初期化
・2-7行目 : 後に使うローカル変数を定義。 sockaddr_in は、インターネット・ソケット・アドレスを含む構造体。これは基本的に、アドレス、ファミリ(我々の目的では常に AF_INET)及びポート番号。i
・8行目 : ここで、バイナリ0で満たすことによりSource を初期化する(0オフセットでmemset() を使うことも出来る)
・9-11行目 : ここで、プロトコル・ファミリにAF_INET (インターネットTCP-IP)を選び、IPアドレスには、クライアントがあらゆるインターフェイスからパケットを受け取るので、特定アドレスの代わりにINADDR_ANY を選ぶ。ポートはOSが空きポートのうちから選ぶが、一旦割り当てるとセッション全体に亘って固定される。 htons() と ntohs() は、ホストからネットワーク及び逆のバイト搬送要求を保証する。
・12-16行目 : ソケットを作る。AF_INET は、インターネットソケットであることを告げる。SOCK_DGRAM は、仮想回路でなくデータグラム配信を用いることを告げる。IPPROTO_UDP は、UDPプロトコル(IPネットワークに起きるデータグラムのための標準トランスポート層プロトコル)の使用を保証する。最後のパラメータとしては一般的に0を渡す。この場合、どのプロトコルを使うかをkernelが解決する。
・17-22行目 : socket()経由でソケットを入手した後の bind() に対する呼出は不要だが、コードの完備と統一のため強く推薦する。この行は、システムにソケットsockfdをアドレスSourceにバインドすることを命じる。
・23行目 : Target を初期化する。
・24-26行目 : ここで、サーバが働くマシンのIPアドレスと同時にそのサーバが聴取するポートをTarget に割り当てる。クライアントとサーバが同一マシン上で走っているときは、 127.0.0.1.を試すこと。
・28-30行目 : リクエストメッセージを構築
・Line 32-35行目 : sendto() システム呼出経由でリクエストメッセージを送る。
・Line 37-40行目 : recvfrom()で応答メッセージを待つ。規定値では、読取るべき新データが到着しなくなるまで recvfrom()がブロックする。しかし、バッファ内で利用することの出来る入力データがないとき、コントロールシステム呼出 fcntl()により、復帰させることが出来る。
・41-46行目 :応答メッセージをプリントする。 inet_aton()を用いて、dotted-decimal ASCII表記をバイナリアドレスに転換する。
・47行目 : ソケットを閉じる。ソケットを閉じた後でも、データ全部をパイプラインに送ろうとする( flag SO_LINGER参照).
server.c
1. int main()
2. {
3. S32 j=-1,sockfd;
4. U32 i,k;
5. PDU_t Pdu;
6. struct sockaddr_in Source, Target;
7. struct in_addr a;
8. bzero ((U8*)&Target,sizeof(Target));
9. Target.sin_family=AF_INET;
10. Target.sin_addr.s_addr=htonl(INADDR_ANY);
11. Target.sin_port=htons(DATA_PORT);
12. bzero ((U8*)&Source,sizeof(Source));
13. if((sockfd=socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP))==-1)
14. {
15. printf ("\n Socket for data msgs cannot be created\n");
16. exit(-1);
17. }
18. /* Now we need to bind it to the os underlying queues */
19. if(bind(sockfd,(struct sockaddr*)&Target,sizeof(Target))==-1)
20. {
21. printf("\n Data socket cannot be binded to OS\n");
22. exit(-1);
23. }
24. k=sizeof(Source);
25. printf("\n...start recvfrom....\n");
26. recvfrom(sockfd,(void*)&Pdu,sizeof(PDU_t),0,(struct sockaddr*)&Source,&k);
27. s_addr=(Source.sin_addr.s_addr);
28. printf("\nReceived from %s at port %d\n",inet_ntoa(a),ntohs(Source.sin_port));
29. printf("\nSender Layer %d\n",((PDU_t)Pdu).SenderLayerid);
30. printf("\nPrimitive %d\n",((PDU_t)Pdu).Primitiveid);
31. printf("\nPdu number %d\n",((PDU_t)Pdu).number);
32. i=((PDU_t)Pdu).number;
33. printf("\n...end recvfrom....\n");
34. Pdu.SenderLayerid=SERVER;
35. Pdu.Primitiveid=RESPONSE;
36. Pdu.number=i;
38. printf("\n...start sendto....\n");
39. k=sendto(sockfd,(void*)&Pdu,sizeof(PDU_t),0,(struct sockaddr*)&Source, sizeof(Source));
40. printf("Packet send to %s at port %d\n",inet_ntoa(a), ntohs(Source.sin_port));
41. printf("\n...end sendto....\n");
42. close(sockfd);
43. }
サーバ内部
使用するapiのほとんどは、クライアントで説明したので、相違だけを述べる。
・ bind() に対する呼出は、サーバに、あらゆるインターフェイスから port = DATA_PORT宛てのリクエストを受け取ることを命じる。
・読者がこれをテストするときは、IPアドレスとポート番号を変更する必要がある。
まとめ
こお記事は、UDPソケットのための簡単なクライアント・サーバ実現を示す。ソケットを用いて作業をするときは、幾つかの事柄に留意する必要がある。第一に、システム呼出全部の戻り値をチェックするのは、良い習慣だ。これでこれらプログラムのデバッグの時間が短くなる。第二に、tcpdump, ethereal, netcatなどのツールをトレースすることは、システムのネットワークインターフェイスの正確な働きを理解するのに役立つ。さらに、オプション a のあるコマンド netstat は、どのソケットが働いているかのチェックに有用なことがある。GDB を通じる単一ステップもまた、このようなコードのデバッグに大変役立つ。
最後に、システムのファイアウォール規則は確実に最低限でなければならない。さもないと、新規データグラムを受け取る間に両プログラムが、うろうろする(ipchainsを点検のこと)。通常、厳密なファイアウォールのあるLinuxでは、クライアントがファイアウォールポート到着不能パケットの形で拒絶応答を受けるが、システムによっては、拒絶応答を送らないで、単に到着パケットを廃棄してしまう。このような状態では、ethereal や tcpdump などのツールが手軽である。私にもそんな経験がある。
shyamjith 提出: 02/28/2004年2月28日 - 05:53
ネットワーク・プロトコル階層は、一つのホストから別のホスト対するにデータの運搬装置とパイプラインを形成するもので、異なる階層に望みのレベルで相互作用することの出来る方法で設計される。この記事は、これら階層を通るデータの動きを記述する目的で、最後にTCP層を出るデータ流を捕捉しそれを表示するのに役立つkernalモジュールの実行を試みる。ネットワーク通信の基本すべてを述べる必要は無いと思うので、 TCP/IP 通信から直接始める。
ネットワーク・プロトコル階層
プロトコル階層の低層からのネットワーク装置で、送受信のため他の装置と交信するためのリンク層プロトコル(通常Ethernet)を使用する。ネットワーク装置ドライバが設定するインターフェイスが物理媒体からパケットをコピイし、何らかのエラーチェックをして、パケットをネットワーク層に置く。出力インターフェイスが、ネットワーク層からパケットを受け取り、何らかのエラーチェックをして、それらを物理媒体を通して送り出す。ここで、標準ネットワーク層プロトコルであるIPについて述べなければならない。IPの主機能はルート決定で、入信パケットがホストコンピュータ用であるか又は、送り出す必要があるかをチェックする。必要ならパケットを分解して、それをトランスポートプロトコルに送る。これは出信パケット用にルートのダイナミック・データベースを有し、それらのアドレスを決め必要ならリンク層に送る前に分割する。
TCP と UDPは最も普通に使われるトランスポート層プロトコルである。UDPは、単にコンピュータ内でポートに対するパケットアドレス決定のための枠組みを与えるだけであるが、TCPは、喪失パケットの復元や通信量管理実行などもっと複雑な接続ベースの動作をすることが出来る。これらはいずれも転送のためアプリケーションパケット負荷をコピイする。
トランスポート層から上にはINET層があり、これがトランスポート層とアプリケーションソケットとの中間層を形成する。INET層は、アプリケーションの所有するソケットを実現する。ソケット固有作動の全ては個々で実行される。
ここでも、更に抽象作用を備えるためBSDソケットの助けを借りて別のインターフェイスが設けられる。BSDは、INETを含む抽象的データ構造体である。ソケットを通じる接続、読取、書込のアプリケーションリクエストは、BSDによりINET作用に転換される。
共通パケット構造体。データはsk_buffと言う共通パケット構造体に包み込まれる。これはデータを運びながら層から層へと移動するので、全ての層がこのデータ構造体を使用する。データがユーザスペースからkernelスペースにコピイされると、sk_buffに入れられて別の層に渡される。一方その層は、これにヘッダを追加する。sk_buffは、パケット、そのソケット、デバイス、ルート、データ位置などに関する情報全てに対するポインタを含む。
ソケット構造体接続確立、データ送受信、IPルート決定については説明することが沢山あるが、全部省略する。ここでは、ネットワーク・プログラマのため、Linuxが作るインターフェイスの種類を見る。
Linux ネットワーク機能
普通のネットワーク・プログラマに取って、Linux kernelのネットワーク・サービスの前線は、次のCライブラリ・ルーチンを通じて利用することが出来る。
socket(), bind(), listen(), connect(), accept(), send(), sendto(), recv(), recvfrom(), getsockopt(), and setsockopt().
socket() ファンクションは、新しいソケットを作るのに用いる。各種プロトコルに伴う作動はソケットを用いて生じる。socket() ルーチンはファイル。デスクリプタを戻すので、read(), write()など通常の作用をこれに適用することが出来る。
bind() ファンクションは、新たに作成するソケットをポートに結合するため用いられる。ポートは、ネットワーク・インターフェイスのIPアドレスと共に、ソケットを独自に識別するため用いられる。ソケットをポートに結合すると、その宛先フィールドにあるポートに到着するパケットはいずれも、ソケット・コントローラに渡される。
listen()ファンクションは、サーバ側プログラム作成に用いられる。ソケットを作ってポートに結合した後、listen()ファンクションを呼び出すと、ソケットは聴取状態に設定される。これは、ソケットが外界のホストからの接続を受けようとすることを意味する。
サーバ側でaccept() ファンクションを呼び出すと、プログラムがブロックして、ソケットが別のホストからの接続要求を受け取るまでソケットを呼び出す。接続が確立したときのみ、プログラムがウエークアップして、外界ホストからのリクエストを処理することが出来る。クライアント側からは、connect() ファンクションを使用して、クライアントがソケットの接続を開いてリクエストを送りたい旨をサーバに知らせる。
不可欠のデータ構造体
ソケット:
この構造体は、BSDソケット・インターフェイス実現の基礎である。システムはsocket()設定を呼び出して、この構造体を初期化する。
sk_buff:
この構造体は、ホストから受発信される個別の通信パケットを管理する。これは入力と出力を一時記憶する。この構造体は、送信のためネットワーク・インターフェイスに送る前、又は処理のため高い層に送り結局アプリケーション層に達する前のいずれかのパケットを保持する。
INET:
この構造体は、ソケットのネットワーク固有部分を管理する。これはTCP, UDP, RAW ソケットに必要である。
proto:
この構造体には、全てのプロトコルに同一の作用多数が含まれる。一度だプログラムされる必要がある処置、エラーを避ける処置を意味する。
sockaddr(sockaddr_in):
これらは、各種アドレスファミリに関する各種アドレスフォーマットをサポートするため必要である。
その他の各種グローバルデータ構造体はkernelスペース (cat/proc/ksyms)で実現される。これら構造体の助けで、Linux kernelに細工をし、各種ネットワーク統計を引き出すことが出来る。また必要があれば、自分のプロトコルを定義することが出来る。プロトコル実行を最適化することも出来る。kernelの細工と新規考案の実現は、能力次第である。新規プロトコルの実行は、この記事の範囲外だが、以下の章では、最小の方法でTCP層に細工する小さいkernelモジュールを設計して実現する。
Linux Kernel モジュール
Linux kernels はモジュールになっている。kernelの一部分(スケジューラなど)は、メモリに常駐するが、その他のプロセスは必要に応じてのみロードされる。ディスク読取用VFATなどは、必要なときのみロードされる。Linux kernel のこの特徴により、kernelスペースを小さくすることが出来る。この場合、モノシリックkernelは通常、追加モジュールを必要としない特注kernelである。
したがって重要なことは、プロトコル、デバイス及び全種類のkernelソフトウエアをkernelモジュールとして設計し、それをユーザスペースからkernelに挿入することが出来ることである。モジュールの挿入又は削除の出来るスーパーユーザであることだけが必要である。kernelモジュールを書く一般フォーマットを示す。基本から出発したいのであれば、基本kernelモジュールを書くための文書をWWWで沢山見出すことが出来る。
#define MODULE
#include
/* ... その他必要なヘッダファイル... */
/*
* ... モジュール宣言とファンクション ...
*/
int init_module() {
/* コード kernel がモジュールをインストールするとき呼び出す */
}
void cleanup_module() {
/* コード kernel がモジュールを削除するとき呼び出す */}
TCP プロトコル細工モジュールの設計
我々のkernelモジュールは極めて簡単だ。仮想的にtcpパケットを送るソケットインターフェイス動作とTCP層との間に置かれる。ここで、TCPプロトコルで登録されたソケットを通って送出されるデータパケットはすべて、我々のkernelモジュールが捕捉する。データは /proc/TCPdata に報告される。cat /proc/TCPdataをして、TCP層を通って出た最新200バイトを見ることが出来る。
使用する重要データ構造体
tcp_prot -> は、実行TCP操作全部に対するポインタを含む。
struct msghdr -> は、アプリケーション及び他のフィールドが上り下りソケットアドレスなどの識別のため送ったデータを含む。
Struct msg_iov -> はmsghdr に含まれる。データに対するポインタを含む。
/Proc
コード作成に入る前に /proc ファイルシステムの重要性について述べたい。procファイルシステムは、殆どのLinuxマシンで/procディレクトリにあるので、こう呼ばれる。このシステムは、非常に強力なツールで、多数のプログラムが頻繁にこれを使用する。これはkernelがそれを使って他のユーザスペースと又は逆に交信することの出来るフレーワークである。ディレクトリ構造とアイノードのあるファイルシステムの一つであるが、実際は、重要変数に関する情報を与える登録ファンクションの構造者である。
/proc にファイルエントリを作るとき、ファイルの読取又は書込のときなすべき事をkernelに命令するファンクションの組と共に登録される。殆どのエントリは読取のみを許し、幾つかが書込も許す。/procエントリに書込をするとき、procエントリに接続されているkernel変数の構成に影響するメッセージをkernelに渡すことを意味する。ここでは、kernelモジュールの中で、データがkernelからユーザスペースに通過するデータを我々が読む事の出来る/procエントリを実行する。
ここで、コード作成に入る。
/* tcpdata.c.
このプログラムは、エントリをprocファイルシステムに設定する方法の例を示す。また、最も重要なことは、TCPプロトコルに細工して、tcp層を通るデータ全部をモニタしてそれを /proc/TCPdataに表示する。
*/
#define MODULE
#define __KERNEL__ /* kernel 作業をしようとする*/
#include
#include
#include /* proc エントリ登録に関する*/
#include
#include
#include
#include
#include
#include
#include
static struct proc_dir_entry *test_entry;
struct msghdr *msg_moniter;
struct iovec *iovec_moniter;
static char *tcp="Tcp monitered data";
int (*orginalSend)(struct sock *, struct msghdr *,int );
/*
show_tcp_stats
このファンクションは、何かが /proc/TCPstat を読み取ろうとするとき /proc FSが呼び出すもので、ソケットからトップ接続を通って外に出る最後の200バイトを見ることが出来る。
*/
static int show_tcp_stats(char *buf,char **start,off_t offset,int len,int unused) {
len += sprintf(buf+len,"%s\n",tcp);
return len;
}
/*
これは tcp sendmsg 呼出を捕捉するハンドラファンクションである。
*/
int moniter_tcp(struct sock *sk, struct msghdr *msg,int len)
{
int size;
char *temp;
printk("I am dangerously monitoring your tcp data \n");
msg_moniter=(struct msghdr *)kmalloc(sizeof(struct msghdr),GFP_KERNEL);
memcpy(msg_moniter,msg,sizeof(struct msghdr));
orginalSend(sk,msg,len);
iovec_moniter=msg_moniter->msg_iov;
size=sizeof(tcp);
printk("sizeof of TCPdat is %d \n",size);
(size<=200)?iovec_moniter==NULL?printk("iovecisnull")
:strcat(tcp,temp=(char*)iovec_moniter->iov_base):strcpy(tcp,"Tcp monitered data");
kfree(msg_moniter);
return len;
}
/*
init_module
このファンクションは、モジュールをインストールする。ディレクトリエントリに /proc FS を登録してポインタ交換を行う。
*/
int init_module() {
test_entry=create_proc_entry( "TCPdata",S_IRUGO,NULL);
test_entry->read_proc=show_tcp_stats;
orginalSend=tcp_prot.sendmsg;
/*
printk("the address of send send mes is %x \n",tcp_prot.sendmsg);
printk("the address of hack mes is %x \n",orginalSend);
*/
tcp_prot.sendmsg=moniter_tcp;
/*
printk("the address of send send mes after hacking %x \n",tcp_prot.sendmsg);
printk("the address of send send mes after hacking %x \n",moniter_tcp);
*/
return 0;
}
/* init_module */
/*
cleanup_module
このファンクションは、モジュールを削除する。単にディレクトリエントリを /proc FS から取消す。
*/
void cleanup_module() {
/* ポインタをtcpの元のメッセージセンダに戻す */
tcp_prot.sendmsg=orginalSend;
/* proc FS からファンクション登録を取消す*/
remove_proc_entry("TCPdata",NULL);
}
/* cleanup_module */
MODULE_AUTHOR("shyamjithe.c.s "); /*macros*/
MODULE_DESCRIPTION("moniter tcp data");
MODULE_LICENSE("GPL");
このプログラムは kernel 2.4 で試験したので、
gcc -O6 -Wall -c tcpdata.c -I /usr/src/linux-2.4.20-8/include/
を用いてコンパイルすることが出来る。
これは tcpdata.oを作る。
今は insmod tcpdata.oになる
幾つかのtcp アプリケーションを開く
cat /proc/TCPdata
モジュールを削除するには、rmmod tcpdataを用いる
コードを理解するため、幾つかのヒントを示す。プログラム全体は、ファンクションのポインタを用いる巧妙な方法ない過ぎないが、ファンクションのポインタを元の中身に戻すのを間違えると、システムが泊まるので注意しなければならない。これはTCP細工の最小の方法だと言った。TCPの上に全く新しいこのような層を作ることが出来る。UDPでも同じことが出来る。興味のある読者が注意深く関係構造体を解析し追跡する課題を差し上げる。これはkernelプログラマになるのに役立つだろう。
tcp_hashinfo -> この構造体は、ソケットバケットを操作するデータエレメントとポインタ及び一定の重要なTCPに基づく情報 tcp_statistics -> を含みTCP統計に関する有用な情報tcp_ioctl などを与える。
まとめ
上述のプログラムから得られる重要な教訓は、プロトコル関連で何か変更をするときkernelソースの変更は必ずしも必要でないと言うことだ。Linux kernelはオブジェクト指向インプレメンテーションで、これによりkernel内のデータオブジェクトの細工をすることが出来る。.