管理されていないコードでの移動:往復

高水準プログラミング言語は人気がありますが、アンマネージドライブラリの実装を使用する必要がある領域があります。これは、特定のOS機能の呼び出し、デバイスへの低レベルのアクセス、アルゴリズムのパフォーマンスの必要性などです。カットの下で、私はあなたがアンマネージドコードで旅行している間に遭遇することができるものとあなたがあなたと一緒に持っていくべきものをあなたに話します。





あなたは居心地の良いIDEの玄関口に立っており、暗くて何もはっきりしないソースコードの世界に行きたくはありません。企業の成功のためには、まず、マップを入手する必要があります。ライブラリのヘッダーの説明が表示されます。完全なドキュメントを用意することをお勧めします。通常は次のようになります。





...
#include <linux/netfilter_ipv4/ip_tables.h>
#include <libiptc/xtcshared.h>

#ifdef __cplusplus
extern "C" {
#endif

#define iptc_handle xtc_handle
#define ipt_chainlabel xt_chainlabel

#define IPTC_LABEL_ACCEPT  "ACCEPT"
#define IPTC_LABEL_DROP    "DROP"
#define IPTC_LABEL_QUEUE   "QUEUE"
#define IPTC_LABEL_RETURN  "RETURN"

/* Does this chain exist? */
int iptc_is_chain(const char *chain, struct xtc_handle *const handle);

/* Take a snapshot of the rules.  Returns NULL on error. */
struct xtc_handle *iptc_init(const char *tablename);

/* Cleanup after iptc_init(). */
void iptc_free(struct xtc_handle *h);
...
      
      



運が良ければ、ドキュメントがそこにあるとしましょう関数のシグネチャ、使用される構造、エイリアス、および他の使用されるヘッダーへの参照について説明します。最初の探求は、OSでライブラリを見つけることです。その名前は、予想されるものとは異なる場合があります。





~$ find /usr/lib/x86_64-linux-gnu/ -maxdepth 1 -name 'libip*'
/usr/lib/x86_64-linux-gnu/libip6tc.so.0.1.0
/usr/lib/x86_64-linux-gnu/libip4tc.so
/usr/lib/x86_64-linux-gnu/libiptc.so.0
/usr/lib/x86_64-linux-gnu/libip4tc.so.0.1.0
/usr/lib/x86_64-linux-gnu/libip6tc.so.0
/usr/lib/x86_64-linux-gnu/libiptc.so.0.0.0
/usr/lib/x86_64-linux-gnu/libip4tc.so.0
/usr/lib/x86_64-linux-gnu/libiptc.so
/usr/lib/x86_64-linux-gnu/libip6tc.so
      
      



数字の接尾辞は、ライブラリのさまざまなバージョンを意味します。一般に、元のlibip4tc.soが必要です。あなたは片目で中を見て、それが価値があることを確認することができます:





~$ nm -D /usr/lib/x86_64-linux-gnu/libip4tc.so
...
0000000000206230 D _edata
0000000000206240 B _end
                 U __errno_location
                 U fcntl
000000000000464c T _fini
                 U __fprintf_chk
                 U free
                 U getsockopt
                 w __gmon_start__
0000000000001440 T _init
0000000000003c80 T iptc_append_entry
0000000000003700 T iptc_builtin
0000000000004640 T iptc_check_entry
0000000000003100 T iptc_commit
0000000000002ff0 T iptc_create_chain
00000000000043f0 T iptc_delete_chain
...
      
      



,   , , . :





public static class Libiptc4
{
        /* Prototype: iptc_handle_t iptc_init(const char *tablename) */
        [DllImport("libip4tc.so")]
        public static extern IntPtr iptc_init(string tablename);
} 
      
      



: . . IntPtr



. , :





/* Prototype: iptc_handle_t iptc_init(const char *tablename) */
[DllImport("libip4tc.so")]
public static extern IntPtr iptc_init(IntPtr tblPtr);
...
var tblPtr = Marshal.StringToHGlobalAnsi("filter");
var _handle = Libiptc4.iptc_init_ptr(tblPtr);
Marshal.FreeHGlobal(tblPtr);
      
      



.



, , , , .





, : . :





struct ipt_entry {
	struct ipt_ip ip;

	/* Mark with fields that we care about. */
	unsigned int nfcache;

	/* Size of ipt_entry + matches */
	__u16 target_offset;
	/* Size of ipt_entry + matches + target */
	__u16 next_offset;

	/* Back pointer */
	unsigned int comefrom;

	/* Packet and byte counters. */
	struct xt_counters counters;

	/* The matches (if any), then the target. */
	unsigned char elems[0];
};
      
      



unsigned char elems[0]



. , , . :





*******************************************
* ip_entry                                *
* 112 bytes                               *
*******************************************
* matches                                 *
* target_offset - 112 bytes               *
*******************************************
* target                                  *
* next_offset - target_offset - 112 bytes *
*******************************************
      
      



(matches



target



) ip_entry



. :





  1. .





  2. .





, , . ipt_entry



:





[StructLayout(LayoutKind.Sequential)]
public struct IptEntry
{
 	public IptIp ip;
	public uint nfcache;
	public ushort target_offset;
	public ushort next_offset;
	public uint comefrom;
	public IptCounters counters;
};
      
      



Marshal.SizeOf<IptEntry>()



112 . matches



target



( ). : libiptc



8 ( long



), . , . :





static readonly int  _WORDLEN = Marshal.SizeOf<long>();
public static int Align(int size)
{
	return ((size + (_WORDLEN - 1)) & ~(_WORDLEN - 1));
}
      
      



, entry.target_offset



entry.next_offset



, :





IntPtr entryPtr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr<IptEntry>(entryPtr, entry, false);
Marshal.StructureToPtr<Match>(entryPtr + 112, match, false);
      
      



:  , , :





var entry = Marshal.PtrToStructure<IptEntry>(point);
var match = Marshal.PtrToStructure<Match>(point + 112)
      
      



, union:







struct xt_entry_match {
	union {
		struct {
			__u16 match_size;

			/* Used by userspace */
			char name[XT_EXTENSION_MAXNAMELEN];
			__u8 revision;
		} user;
		struct {
			__u16 match_size;

			/* Used inside the kernel */
			struct xt_match *match;
		} kernel;

		/* Total length */
		__u16 match_size;
	} u;

	unsigned char data[0];
};
      
      



Union - : . c#. . , ( ). .





:





#define XT_EXTENSION_MAXNAMELEN   29
...
char name [XT_EXTENSION_MAXNAMELEN]
      
      



. header .





, . ushort, uint long , . . : , . . . :





byte [] convArray = BitConverter.GetBytes(value);
Array.Reverse(convArray);
ushort reverseEndian = BitConverter.ToUInt16(convArray,0);
      
      



ushort reverseEndian = (ushort)((value << 8) | (value >> 8));
      
      



. unmanaged code . /, errno. . , :





[DllImport("libip4tc.so", SetLastError = true)]
      
      



, , :





int errno = Marshal.GetLastWin32Error();
var errPtr = Libiptc4.iptc_strerror(errno);
string errStr = Marshal.PtrToStringAnsi(errPtr);
      
      



Linux c net.core (, /). : -, 32/64 , Windows . .





これで私たちの旅は終わりです。低レベルのライブラリを使用することは、成功の観点からは困難で予測不可能なアプローチのように思われることを付け加えておきます。ドキュメントの欠如と複雑な相互作用は恐ろしいことがあります。ただし、これが目的の結果を達成する唯一の方法である場合があります。








All Articles