マイペースなプログラミング日記

DTMやプログラミングにお熱なd-kamiがマイペースに書くブログ

IPヘッダを表すクラスを作成してみた

VpnServiceを使ってIPパケットを取得できたのでIPヘッダを表すクラスを作成した。読み込んだパケットをsetする。ちょっと長くなってしまった。最初の来るパケットはUDPっぽいので次はUDPヘッダクラスを作成する

package net.d_kami;

/**
 * IPv4ヘッダを表すクラス。送信元IPアドレスや送信先IPアドレスを格納する
 * 
 * @author d-kami
 */
public class IPHeader{
    /** このIPヘッダのバージョン */
    private int version;
    
    /** このヘッダの長さ */
    private int headerLength;
    
    /** IPパケットの優先順位 */
    private int serviceType;
    
    /** IPパケットの長さ */
    private int packetLength;
    
    /** 識別番号 */
    private int id;
    
    /** IPパケットの分割を行うかどうかのフラグ */
    private int flag;
    
    /** 分割されたパケットが元のパケットのどの位置にあるか */
    private int offset; 
    
    /** 生存時間 */
    private int ttl;
    
    /** 上位層のプロトコル番号 */
    private int protocol;
    
    /** チェックサム */
    private int checksum;
    
    /** 送信元IPアドレス */
    private String srcAddress;
    
    /** 送信先IPアドレス */
    private String dstAddress;

    /**
     * パケットをIPパケットと見なしてIPヘッダに値を設定する
     * 
     * @param packet 解析するパケット
     */
    public void set(byte[] packet){
        if(packet == null || packet.length < 20){
            throw new IllegalStateException("渡されたパケットはIPv4パケットではありません");
        }

        setVersion(packet);
        setHeaderLength(packet);
        setServiceType(packet);
        setPacketLength(packet);
        setId(packet);
        setFlag(packet);
        setOffset(packet);
        setTtl(packet);
        setProtocol(packet);
        setChecksum(packet);
        setSrcAddress(packet);
        setDstAddress(packet);
    }
    
    /**
     * このIPヘッダのバージョンをパケットから設定する
     * 
     * @param packet IPヘッダのバージョンが格納されているパケット
     */
    private void setVersion(byte[] packet){
        version = (packet[0] >> 4) & 0x0F;
    }
    
    /**
     * このIPヘッダのバージョンを設定する
     * 
     * @param version このIPヘッダのバージョン
     */
    public void setVetsion(int version){
        this.version = version;
    }
    
    /**
     * このIPヘッダのバージョンを返す
     * 
     * @return このIPヘッダのバージョン
     */
    public int getVersion(){
        return version;
    }
    
    /**
     * このIPヘッダの長さをパケットから設定する
     * 
     * @param packet このIPヘッダの長さを格納したパケット
     */
    private void setHeaderLength(byte[] packet){
        headerLength = packet[0] & 0x0F;
    }
    
    /**
     * このIPヘッダの長さを設定する
     * 
     * @param headerLength このIPヘッダの長さ
     */
    public void setHeaderLength(int headerLength){
        this.headerLength = headerLength;
    }
    
    /**
     * このIPヘッダの長さを返す
     * 
     * @return このIPヘッダの長さ
     */
    public int getHeaderLength(){
        return headerLength;
    }
    
    /**
     * このIPパケットの優先順位をパケットから設定する
     * 
     * @param packet このIPパケットの優先順位を格納したパケット
     */
    private void setServiceType(byte[] packet){
        serviceType = packet[1] & 0xFF;
    }
    
    /**
     * このIPパケットの優先順位を設定する
     * 
     * @param packet このIPパケットの優先順位
     */
    public void setServiceType(int serviceType){
        this.serviceType = serviceType;
    }
    
    /**
     * このIPパケットの優先順位を返す
     * 
     * @return このIPパケットの優先順位
     */
    public int getServiceType(){
        return serviceType;
    }
    
    /**
     * このIPパケットの長さをパケットから設定する
     * 
     * @param packet このIPパケットの長さを格納したパケット
     */
    public void setPacketLength(byte[] packet){
        packetLength = ((packet[2] & 0xFF) << 8) + (packet[3] & 0xFF);
    }
    
    /**
     * このIPパケットの長さを設定する
     * 
     * @param packet このIPパケットの長さ
     */
    public void setPacketLength(int packetLength){
        this.packetLength = packetLength;
    }
    
    /**
     * このIPパケットの長さを返す
     * 
     * @return このIPパケットの長さ
     */
    public int getPacketLength(){
        return packetLength;
    }
    
    /**
     * このIPパケットの識別番号をパケットから設定する
     * 
     * @param packet このIPパケットの識別番号を格納したパケット
     */
    private void setId(byte[] packet){
        id = ((packet[4] & 0xFF) << 8) + (packet[5] & 0xFF);
    }
    
    /**
     * このIPパケットの識別番号を設定する
     * 
     * @param packet このIPパケットの識別番号
     */
    public void setId(int id){
        this.id = id;
    }
    
    /**
     * このIPパケットの識別番号を返す
     * 
     * @return このパケットの識別番号
     */
    public int getId(){
        return id;
    }
    
    /**
     * このIPパケットが分割されてるかどうかのフラグをパケットから設定する
     * 
     * @param packet このIPパケットが分割されてるかどうかのフラグを格納したパケット
     */
    private void setFlag(byte[] packet){
        flag = (packet[6] & 0xFF) >> 5;
    }
    
    /**
     * このIPパケットが分割されてるかどうかのフラグを設定する
     * 
     * @param packet このIPパケットが分割されてるかどうかのフラグ
     */
    public void setFlag(int flag){
        this.flag = flag;
    }
    
    /**
     * このIPパケットが分割されているかどうかのフラグを返す
     * 
     * @return このIPパケットが分割されているかどうかのフラグ
     */
    public int getFlag(){
        return flag;
    }
    
    /**
     * このIPパケットの分割前のオフセットをパケットから設定する
     * 
     * @param packet このIPパケットの分割前のオフセットを格納したパケット
     */
    private void setOffset(byte[] packet){
        offset = ((packet[6] & 0x1F) << 8) + packet[7] & 0xFF;
    }
    
    /**
     * このIPパケットの分割前のオフセットを設定する
     * 
     * @param packet このIPパケットの分割前のオフセット
     */
    public void setOffset(int offset){
        this.offset = offset;
    }
    
    /**
     * このIPパケットの分割前のオフセットを返す
     * 
     * @return このIPパケットの分割前のオフセット
     */
    public int getOffset(){
        return offset;
    }
    
    /**
     * このIPパケットの生存時間をパケットから設定する
     * 
     * @param packet このIPパケットの生存時間を格納したパケット
     */
    private void setTtl(byte[] packet){
         ttl = packet[8] & 0xFF;
    }
    
    /**
     * このIPパケットの生存時間を設定する
     * 
     * @param packet このIPパケットの生存時間
     */
    public void setTtl(int ttl){
         this.ttl = ttl;
    }
    
    /**
     * このIPパケットの生存時間を返す
     * 
     * @return このIPパケットの生存時間
     */
    public int getTtl(){
        return ttl;
    }
    
    /**
     * このIPパケットの上位層のプロトコル番号をパケットから設定する
     * 
     * @param packet このIPパケットの上位層のプロトコル番号を格納したパケット
     */
    private void setProtocol(byte[] packet){
        protocol = packet[9] & 0xFF;
    }
    
    /**
     * このIPパケットの上位層のプロトコル番号を設定する
     * 
     * @param packet このIPパケットの上位層のプロトコル番号
     */
    public void setProtocol(int protocol){
        this.protocol = protocol;
    }

    /**
     * このIPパケットの上位層のプロトコル番号を返す
     * 
     * @return このIPパケットの上位層のプロトコル番号
     */
    public int getProtocol(){
        return protocol;
    }
    
    /**
     * このIPパケットのチェックサムをパケットから設定する
     * 
     * @param packet このIPパケットのチェックサムを格納するパケット
     */
    private void setChecksum(byte[] packet){
        checksum = ((packet[10] & 0xFF) << 8) + packet[11] & 0xFF;
    }
    
    /**
     * このIPパケットのチェックサムを設定する
     * 
     * @param packet このIPパケットのチェックサム
     */
    public void setChecksum(int checksum){
        this.checksum = checksum;
    }
    
    /**
     * このIPパケットのチェックサムを返す
     * 
     * @return このIPパケットのチェックサム
     */
    public int getChecksum(){
        return checksum;
    }
    
    /**
     * このIPパケットの送信元アドレスをパケットから設定する
     * 
     * @param packet このIPパケットの送信元アドレスを格納するパケット
     */
    private void setSrcAddress(byte[] packet){
        srcAddress = ip2Str(packet, 12);
    }
    
    /**
     * このIPパケットの送信元アドレスを設定する
     * 
     * @param packet このIPパケットの送信元アドレス
     */
    public void setSrcAddress(String srcAddress){
        this.srcAddress = srcAddress;
    }
    
    /**
     * このIPパケットの送信元アドレスを返す
     * 
     * @return このIPパケットの送信元アドレス
     */
    public String getSrcAddress(){
        return srcAddress;
    }
    
    /**
     * このIPパケットの送信先アドレスをパケットから設定する
     * 
     * @param packet このIPパケットの送信先アドレスを格納するパケット
     */
    private void setDstAddress(byte[] packet){
        dstAddress = ip2Str(packet, 16);
    }
    
    /**
     * このIPパケットの送信先アドレスを設定する
     * 
     * @param packet このIPパケットの送信先アドレス
     */
    public void setDstAddress(String srcAddress){
        this.srcAddress = srcAddress;
    }
    
    /**
     * このIPパケットの送信先アドレスを返す
     * 
     * @return このIPパケットの送信先アドレス
     */
    public String getDstAddress(){
        return dstAddress;
    }
    
    /**
     * このIPヘッダをbyte配列に変換する
     * 
     * @return このIPヘッダをbyte配列に変換したもの
     */
    public byte[] toByteArray(){
        byte[] array = new byte[20];
        array[0] = (byte)((((version & 0xFF) << 4) | (headerLength & 0xFF)) & 0xFF);
        array[1] = (byte)(serviceType & 0xFF);
        array[2] = (byte)((packetLength >> 8) & 0xFF);
        array[3] = (byte)(packetLength & 0xFF);
        array[4] = (byte)((id >> 8) & 0xFF);
        array[5] = (byte)(id & 0xFF);
        array[6] = (byte)((((flag & 0xFF) << 5) | ((offset >> 8) & 0xFF)) & 0xFF);
        array[7] = (byte)(offset & 0xFF);
        array[8] = (byte)(ttl & 0xFF);
        array[9] = (byte)(protocol & 0xFF);
        array[10] = (byte)((checksum >> 8) & 0xFF);
        array[11] = (byte)(checksum & 0xFF);
        str2IP(array, 12, srcAddress);
        str2IP(array, 16, dstAddress);

        return array;
    }

    /**
     * 文字列のIPアドレスからbyte型の配列に格納する
     * 
     * @param array 格納先byte配列
     * @param index 格納先index
     * @param ip 文字列のIPアドレス
     */
    private void str2IP(byte[] array, int index, String ip){
        String[] split = ip.split("\\.");
        
        for(int i = 0; i < 4; i++){
            array[index + i] = Byte.parseByte(split[i]);
        }
    }

    /**
     * byte配列のIPアドレスを文字列に変換する
     * 
     * @param packet IPアドレスを格納するbyte配列
     * @param index IPアドレスが始まるindex
     * @return IPアドレスの文字列表現
     */
    private String ip2Str(byte[] packet, int index){
        return String.format("%d.%d.%d.%d", packet[index] & 0xFF, packet[index + 1] & 0xFF, packet[index + 2] & 0xFF, packet[index + 3] & 0xFF);
    }
}