منبع اصلی نوشتار زیر در این لینک قرار دارد

چرا گنو/لینوکس را دوست دارم؟

چرا گنو/لینوکس را دوست دارم؟

چرا گنو/لینوکس را دوست دارم؟

وقتی برای اولین بار گنو/لینوکس نصب کردم، شاید به خاطر تغییر، احساس راحتی با سیستم‌عامل جدیدم نداشتم ولی همینطور که زمان می‌گذشت همه چیز راحت‌تر از حتی ویندوز بود که فکر می‌کردم بهترین سیستم‌عامل دنیاست. اوبونتوی ۷.۰۴ اولین توزیعی نبود که نصب کردم ولی همین توزیع باعث شد گنو/لینوکس رو به عنوان سیستم‌عامل مورد علاقم انتخاب کنم. نزدیک به ۶ سال می‌گذره و امروز به بهانهٔ مسابقهٔ «چرا گنو/لینوکس را دوست دارم؟» تصمیم گرفتم دلایل خودم رو برای گنو/لینوکسی بودن بنویسم.

پیش از این بارها در در مورد گنو/لینوکس نوشتم، مطالبی که شاید برای خودم جذابیت داشتن، مثل «کامپایلر و IDE پاسکال برای گنو/لینوکس» یا جذابیت‌های گرافیکی گنو/لینوکس و البته «تغییر تصویر زمینه‌ی صفحه‌ی بوت سیستم» یا حتی از ابزار‌هایی که گنو/لینوکس در اختیار کاربر می‌ذاره مثل «split» و «mencoder» و «aria2» و «youtube-dl» و «wget» یا حتی عمیق‌تر شدم به موضوع‌هایی که شاید فراتر از یک نرم‌افزار بوده؛ مثل «Slax، سیستم عامل جیبی شما» یا در مورد «FriendFeed در خط‌فرمان» نوشتم یا حتی وقتی بیشتر یاد گرفتم، خودم اسکریپت‌های مختلفی نوشتم که کار‌های روزمره رو برای من ساده تر کنه. مثل «dentinal». و خیلی از چیز‌ها رو هم توی گنو/لینوکس برای خودم شخصی کردم که در موردشون ننوشتم. به عنوان مثال این که زبان صفحه‌کلیدم با Caps Lock عوض بشه چون به نظرم هیچوقت از Caps Lock استفاده نمی‌کردم. یا با ترکیب md5sum و split و با کمک diff وقتی یک فایل بد دانلود شده بود، قسمت ناقص فایل رو پیدا می‌کردم و فقط اون قسمت رو دانلود مجدد می‌کردم. یا حتی اسکرپیت‌هایی که فیلم‌ها من رو مرتب کنه و مشخصات اون‌ها رو از IMDB بگیره و کنار فیلم بذاره. یا اسکریپتی که زیر‌نویس‌هایی که از اینترنت برای فیلم‌ها می‌گیرم رو مرتب می‌کنه، انکدینگشون رو عوض می‌کنه و کاراکترهای فارسی رو جایگذین غیر فارسی‌ها می‌کنه.

اما این‌ها جذابیت‌هایی نیستن که بگم گنو/لینوکس رو فقط به خاطر این‌ها دوست دارم. اگر مثل یک هکر عمیق‌تر نگاه کنیم، انجام تمام این کارها توی هر سیستم‌عاملی ممکنه؛ حتی سیستم‌عاملی به جالبی Femto OS. خیلی از نرم‌افزار‌های آزاد که به صورت روزمره استفاده می‌کنیم، برای سیستم‌عامل‌های دیگه هم وجود دارن. نرم‌افزار‌های بسته هم زیاد هستن که خیلی از نیاز‌های ما رو برطرف می‌کنن؛ ولی در بد ترین حالت، نرم‌افزار‌های آزاد رو برای سیستم‌عامل مقصد کامپایل و اجرا می‌کنیم. پیش‌تر هم در این مورد نوشتم: «چگونه از کامپایلر‌های متن باز در ویندوز استفاده کنیم».

اما مهم‌ترین دلیل من برای دوست‌داشتن گنو/لینوکس، «آزاد بودن» اونه. شاید اگر بنویسم آزادی یعنی:

  • آزادی برای اجرای برنامه برای هر منظوری (آزادی ۰)
  • آزادی برای مطالعه و بررسی چگونگی عملکرد برنامه و تغییر آن برای نیاز خود (آزادی ۱). دسترسی به کد منبع یک پیش‌شرط برای این آزادی می‌باشد.
  • آزادی برای توزیع مجدد کپی‌هایی از آن، بنابراین شما می‌توانید به همسایگان خود کمک کنید (آزادی ۲).
  • آزادی برای بهبود برنامه و انتشار این تغییرات برای عموم، بنابراین تمام جامعه از آن بهره می‌برند (آزادی ۳). دسترسی به کد منبع یک پیش‌شرط برای این آزادی می‌باشد.

خیلی تکراری حرف زده باشم. ولی باور کنید این چیزیه که خیلی از سیستم‌عامل‌های دیگه (و البته نه همه) ندارن. وارد بحث‌های جانبی که آزادی باعث پیشرفت علم کامپیوتر شده و موارد مشابه نمی‌شم. خیلی وقتا، حتی با کسانی که تازه گنو/لینوکسی شدن، این بحث پیش میاد که این سطوح آزادی آیا به درد ما می‌خوره؟ ما می‌خوایم سیستم‌عامل کار کنه و بقیه هم کار می‌کنن. اما برای من موردی پیش اومد که آزاد بودن سیستم‌عامل به من کمک کرد تا به هدف برسم و بدون آزادی سیستم‌عامل این کار غیر ممکن بود.

بذارین با یکم توضیح شروع کنم. اطلاعاتی که به لایهٔ TCP شبکه فرستاده می‌شن، تو یک غلاف جا می‌گیرن و اطلاعات لازم برای رسیدن به پروسهٔ مقصد بهشون اضافه می‌شه. بیت‌های ۱۰۰، ۱۰۱ و ۱۰۲ (اگر شماره رو اشتباه نگفته باشم) رزرو شده هستن و صفر در اون‌ها قرار می‌گیره. تو دانشگاه یک بار بحث پیش اومد که از این بیت‌ها می‌شه استفاده‌های مختلفی کرد. به عنوان مثال این بیت‌ها می‌تونن شمارهٔ کلید رمز‌نگاری/رمز‌گشایی بسته‌ای باشن که توی یک سازمان تعریف شده؛ بسته‌هایی که روی شبکه قرار می‌گیرن، بر اساس مقصد رمز‌نگاری خاصی داشته باشن. از طرفی روند عادی شبکه نباید تغییر کنه و به عنوان مثال مدیر که به همهٔ کلید‌ها دسترسی داره باز هم باید بتونه بسته‌های عادی خودش رو به شبکه (مثل اینترنت، با بیت‌های رزرو شدهٔ صفر) ارسال کنه. از نظر فنی، سیستم‌عامل وظیفهٔ بسته بندی اطلاعات رو بر عهده داره پس ایجاد این روند برای یک سازمان نیاز به تغییر سیستم‌عامل و البته بازنویسی یا تغییر کد اون قسمت از سیستم‌عامله.

TCP Header

هدر بستهٔ TCP

اما آیا این کار عملیه یا فقط در سطح ادعاست؟

من شروع به مطالعه کردم و به این نتیجه رسیدم که یک جائی از کد سیستم‌عامل باید اینطور چیزی نوشته شده باشه (البته این کد خاص، قسمتی از کدیه که به عنوان پروتوتایپ نوشتم و البته همونطور که معلومه قسمتی از رفتار سیستم‌عامل برای مدیریت TCP رو نشون می‌ده):

	// TCP Header
	tcpheader->seq = seq; // Sequence Number
	tcpheader->ack_seq = 0; // Acknowledgment Number
	tcpheader->doff = 5; // Segment offset (Length of the header)
	tcpheader->window = htons(4500) + rand() % 1000;// Window size
	tcpheader->urg_ptr = 0; // Urgent pointer.
	tcpheader->source = saddr.sin_port; // Source Port
	tcpheader->dest = daddr.sin_port; // Destination Port
	tcpheader->check = 0; // Checksum. (Zero until computed)
	tcpheader->syn = 1;

و کاری که من باید انجام بدم اینه که بیام به اینطور رفتار، چیزی مثل کد زیر رو اضافه کنم:

	tcpheader->res1 = key_index;

و البته پیلود رو هم با کلید encrypt کنم و فیلد‌های بسته رو بر اساس تغییر پیلود تغییر بدم. لینوکس (کرنل) آزاد بود پس به راحتی می‌شد سورس‌کدش رو دید، تغییر داد و منتشر کرد. پس این کار رو کردم. آخرین نسخهٔ کرنل رو از سایت Kernel.org دانلود کردم و تو کد قستمی که بسته‌های TCP رو اداره می‌کنه پیدا کردم.

ramin@ramin-host:~/programming/kernel/linux-3.7.2/net/ipv4$ ls tcp*
tcp_bic.c   tcp_cubic.c     tcp_highspeed.c  tcp_illinois.c  tcp_lp.c          tcp_minisocks.c  tcp_scalable.c  tcp_vegas.h     tcp_yeah.c
tcp.c       tcp_diag.c      tcp_htcp.c       tcp_input.c     tcp_memcontrol.c  tcp_output.c     tcp_timer.c     tcp_veno.c
tcp_cong.c  tcp_fastopen.c  tcp_hybla.c      tcp_ipv4.c      tcp_metrics.c     tcp_probe.c      tcp_vegas.c     tcp_westwood.c

و البته از اونجا که کد به اندازهٔ خوبی مستند شده، قستم‌هائی رو که می‌خواستم پیدا کردم. به عنوان مثال کد زیر قستمی از کد کرنله که بسته با فلگ ACK رو ارسال می‌کنه :


/* The code following below sending ACKs in SYN-RECV and TIME-WAIT states
   outside socket context is ugly, certainly. What can I do?
 */

static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
			    u32 win, u32 ts, int oif,
			    struct tcp_md5sig_key *key,
			    int reply_flags, u8 tos)
{
	const struct tcphdr *th = tcp_hdr(skb);
	struct {
		struct tcphdr th;
		__be32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2)
#ifdef CONFIG_TCP_MD5SIG
			   + (TCPOLEN_MD5SIG_ALIGNED >> 2)
#endif
			];
	} rep;
	struct ip_reply_arg arg;
	struct net *net = dev_net(skb_dst(skb)->dev);

	memset(&rep.th, 0, sizeof(struct tcphdr));
	memset(&arg, 0, sizeof(arg));

	arg.iov[0].iov_base = (unsigned char *)&rep;
	arg.iov[0].iov_len  = sizeof(rep.th);
	if (ts) {
		rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
				   (TCPOPT_TIMESTAMP <source;
	rep.th.source  = th->dest;
	rep.th.doff    = arg.iov[0].iov_len / 4;
	rep.th.seq     = htonl(seq);
	rep.th.ack_seq = htonl(ack);
	rep.th.ack     = 1;
	rep.th.window  = htons(win);

#ifdef CONFIG_TCP_MD5SIG
	if (key) {
		int offset = (ts) ? 3 : 0;

		rep.opt[offset++] = htonl((TCPOPT_NOP << 24) |
					  (TCPOPT_NOP << 16) |
					  (TCPOPT_MD5SIG <saddr,
				    ip_hdr(skb)->daddr, &rep.th);
	}
#endif
	arg.flags = reply_flags;
	arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
				      ip_hdr(skb)->saddr, /* XXX */
				      arg.iov[0].iov_len, IPPROTO_TCP, 0);
	arg.csumoffset = offsetof(struct tcphdr, check) / 2;
	if (oif)
		arg.bound_dev_if = oif;
	arg.tos = tos;
	ip_send_unicast_reply(net, skb, ip_hdr(skb)->saddr,
			      ip_hdr(skb)->daddr, &arg, arg.iov[0].iov_len);

	TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
}

با کمی دقت کد زیر شبیه که به کدی که انتظار داشتم، پیدا می‌شه:

	/* Swap the send and the receive. */
	rep.th.dest    = th->source;
	rep.th.source  = th->dest;
	rep.th.doff    = arg.iov[0].iov_len / 4;
	rep.th.seq     = htonl(seq);
	rep.th.ack_seq = htonl(ack);
	rep.th.ack     = 1;
	rep.th.window  = htons(win);

در هر صورت، وارد بحث‌های فنی و جزئیات پیاده سازی نمی‌شم. ولی هدفم از این مثال تاکید به آزادی برای مطالعه و بررسی چگونگی عملکرد برنامه و تغییر آن برای نیاز خود به عنوان یکی از سطوح آزادی سیستم‌عامل بود. چیزی که خیلی از سیستم‌عامل‌ها، حتی اگر بهتر باشن، قوی‌تر باشن، زیبا تر باشن، نرم‌افزار‌های بهتری داشته باشن، بازی‌های بهتری روی اون‌ها اجرا بشه و… از اون بی‌بهره هستن.

شاید این تصور به وجود بیاد که این آزادی‌ها، برای من به عنوان یک برنامه‌نویس مفید بوده. ولی می‌شه به این فکر کرد که اگر من، یک دانشجوی کامپیوتر، تونستم به این قسمت از سیستم‌عامل برسم، اون رو بخونم و یاد‌بگیرم، بر اساس نیاز تغییرش بدم و اون رو منتشر کنم، پس خیلی از حرفه‌ای‌ها تو دنیا هم می‌تونن این کار رو انجام بدن. از ۱۹۹۱ که لینوکس ساخته شده تا به امروز هزاران نفر این سیستم‌رو مرور کردن و تغییر دادن و بهینه کردن. پس با خیال راحت می‌تونم به سیستم‌عاملم اعتماد کنم و یقین داشته باشم که یکی از بهینه‌ترین سیستم‌عامل‌های ساخته شده رو در اختیار دارم. بدون دغدغه‌های مثل بد افزار‌ها. این درحالیه که تعداد خیلی کمتری از آدما کد سیستم‌عامل‌های بسته رو دیدن و مرور کردن، از کلی بد‌افزار که وجود دارن اگر بگذریم، مواردی مثل «قهرمان‌ باگ‌های امنیتی ویندوز: اجرای کد ریموت با TCP/IP» وجود دارن که شاید برای یک گنو/لینوکسی غیر قابل باور باشن.

پس با افتخار می‌نویسم: گنو/لینوکس رو دوست دارم چون آزاده و به آزادی کاربرش احترام می‌ذاره.

و در درجهٔ بعد قدرت، امکانات، جامعهٔ کاربری، امنیت، بهینگی و البته مواردی که هرچقدر بیشتر یاد‌می‌گیرم، بیشتر می‌شن؛ دلایلی هستن که من گنو/لینوکسی هستم و اون رو دوست دارم.

پـ. نـ.: دروغ چرا، وقتی توی سیستم‌عاملی هستم که چیزی مثل ترمینال گنو/لینوکس نداره (یعنی تو ویندوزم!) کامپیوتر یه موجود غریبه می‌شه برام. دست توسعه‌دهنده‌های Cygwin درد نکنه.
پـ. نـ.: یه ضرب‌المثل هست که می‌گه یه گیک یک کار رو ۳ بار انجام نمی‌ده، یه اسکریپت می‌نویسه.

چرا گنو/لینوکس را دوست دارم؟




برچسب ها : , , , , , ,