Roads to Node Blog

アクセスカウンタ

help RSS 今日のネットワーク

<<   作成日時 : 2009/07/08 23:40   >>

ナイス ブログ気持玉 7 / トラックバック 0 / コメント 1

気温が高い事よりも、湿度が高いのがまいる。

あんまり暑いと用もないのにサーバールーム行きたくなるよね。
っていうか、あそこに机置きたいわ、夏は。

最近、仕事でプログラム関係が多かったりする。
おかしいなぁ、どっちかって言うと、ネットワーク・セキュリティですよね?なんでこんなプログラミングだの、システム分析だの設計だのの話してるんだろう。
慣れない分疲労が激しいです。

んで、本家「Roads to Node」のBBSの方に。
C#で作ったリゾルバの書き込みがあって。

う〜ん。C#わからんしなぁ…。
…Javaで作ってみるかぁ。最近、ちょっとだけソケットがらみの勉強してるし…。

で、できたのがコレ。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class DNSResolver {
  private static final int TIMEOUT = 3000;
  private static final int PORT = 53;
  private static final int ROOT = 0;
  private static final int PACKETLENGTH = 1024;
  public static void main(String[] args) throws Exception{
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    //DNSサーバと、質問するドメイン名の入力
    System.out.print("DNSサーバ:");
    String dnsServer = br.readLine();
    System.out.print("ドメイン名:");
    String domainName = br.readLine();
    //DNSサーバ名の解決
    InetAddress svrAddr = InetAddress.getByName(dnsServer);
    //バイト型のラベル配列
    ArrayList<Byte> labelData = new ArrayList<Byte>();
    //ドメイン名をTokenizerで分割してラベルにする
    StringTokenizer st = new StringTokenizer(domainName,".");
    while(st.hasMoreTokens()){
      String label = st.nextToken();
      //ラベル長をラベル配列にいれる
      int labelLength = label.length();
      labelData.add(new Integer(labelLength).byteValue());
      //ラベルをASCIIでバイト型にして、ラベル配列に入れる
      byte labelString[] = label.getBytes("ASCII");
      for(int i=0;i<labelString.length;i++){
        labelData.add(new Byte(labelString[i]));
      }
    }
    //ラベル配列の最後にルートドメインを示す0x0を入れる
    labelData.add(new Byte(new Integer(ROOT).byteValue()));
    //DNSヘッダセクション ID=1、フラグ、QDCount=1 その他カウント=0
    byte header[] = {0x00,0x01,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00};
    //ラベル配列をバイト型の配列に入れる
    byte QName[] = new byte[labelData.size()];
    for(int i=0;i<labelData.size();i++){
      QName[i] = labelData.get(i).byteValue();
    }
    //QType=A
    byte QType[] = {0x00,0x01};
    //QClass=IN
    byte QClass[] = {0x00,0x01};
    //DNSメッセージ長
    int totalByte = header.length + QName.length + QType.length + QClass.length;
    //送信用のバイト型配列を作成し、ヘッダ、QName、QType、QClassを入れる
    byte queryData[] = new byte[totalByte];
    System.arraycopy(header,0,queryData,0,header.length);
    System.arraycopy(QName,0,queryData,header.length,labelData.size());
    System.arraycopy(QType,0,queryData,header.length+labelData.size(),QType.length);
    System.arraycopy(QClass,0,queryData,header.length+labelData.size()+QType.length,QClass.length);
    //ソケット生成
    DatagramSocket socket = new DatagramSocket();
    //タイムアウトの設定
    socket.setSoTimeout(TIMEOUT);
    //送信用データグラム
    DatagramPacket query = new DatagramPacket(queryData,queryData.length,svrAddr,PORT);
    //受信用バッファ
    byte replyData[] = new byte[PACKETLENGTH];
    //受信用データグラム
    DatagramPacket reply = new DatagramPacket(replyData,PACKETLENGTH);
    //データグラム送信
    socket.send(query);
    //データグラム受信
    socket.receive(reply);
    //受信したバイトをString型に変換し、出力
    String data = new String(reply.getData(),0,reply.getLength(),"ASCII");
    System.out.println(data);
  }
}

一応ネームサーバとやりとりができるところまでは確認した。
まぁ、ReplyはビットをそのままStringで出力してるからまともに読めないけど。
やりとりをキャプチャして、正しく動いているっぽいのでOK。

あと、とりあえず動くものを作ったので、例外処理がないのはご愛嬌。

う〜ん、面白いことは面白いな、プログラミング。
リゾルバなんか作ったら、今度はサーバを作りたくなったりして。まぁ、難易度が全然違うけれど。

改めて見直すと、もっとスマートになりそうな気がする。
気はするのだが、どうしていいかわからないのが困りもの。
そこらへんは、教えてもらったり、本で読んだりしないと身につかないものだからなぁ。
もうちょっと勉強するかなぁ……。

自分のサイト見て、DNSメッセージフォーマット見て、それをそのまま送る、というだけのものだしな。
あぁ、そうそう。DNSを学ぶなら、おススメの本がありますよ?

3分間DNS基礎講座
技術評論社
網野 衛二


Amazonアソシエイト by ウェブリブログ


と、うまく宣伝にもっていけたところで今日はここまで。


そんな一日

テーマ

関連テーマ 一覧

月別リンク

ブログ気持玉

クリックして気持ちを伝えよう!
ログインしてクリックすれば、自分のブログへのリンクが付きます。
→ログインへ
気持玉数 : 7
ナイス ナイス ナイス ナイス
面白い 面白い
ガッツ(がんばれ!)

トラックバック(0件)

タイトル (本文) ブログ名/日時

トラックバック用URL help


自分のブログにトラックバック記事作成(会員用) help

タイトル
本 文

コメント(1件)

内 容 ニックネーム/日時
WireShark+Winpcapを使ってnslookupと同じバイト配列を流してみたら成功。どうやらちゃんと処理が進んだ。

#以前使っていたマシンで何故かWireSharkが上手く動かなかったっぽかったので,このマシンに入れるのを敬遠してたんです。

#また別の"以前"にですね,Integerをバイト配列にしたら数値の低い方が先に来た覚えがあり,それが頭にあったから今回QDCOUNTの1を0x00 0x01ではなく0x01 0x00にしていたんです。

#どこかで(別のサイトのPDFだったかも),文字数が2バイトで表現されているところがあって,それでどっちだーとか思いながら2バイトにしていたが,指摘どおり,1バイトにしなおした。

後やってないのはフラグの検証かな。
himajin100000
2009/07/09 19:19

コメントする help

ニックネーム
URL(任意)
本 文
今日のネットワーク Roads to Node Blog/BIGLOBEウェブリブログ
[ ]