วันจันทร์ที่ 22 สิงหาคม พ.ศ. 2559

ทดลองส่งข้อมูลผ่านฟอร์มแบบอัตโนมัติ โดยใช้ php curl วิธี GET

หลังจากที่ผู้เขียนได้ทดลองการส่งข้อมูลผ่านฟอร์มแบบอัตโนมัติโดยไม่ต้องคอยนั่งกดคีย์ Submit ไปเมื่อปี 2558 ตามลิงค์ที่ให้นี้ http://www.s-techthai.com/2014/12/php-method-post.html กลับมาเจอการบ้านใหม่อีกครั้งเพราะการส่งข้อมูลใช้วิธีการที่เรียกว่า "POST" มีบางแอพพลิเคชั่นที่ไม่ต้องการให้เราสั่งงานโดยใช้การ "POST" มาในวันที่จะเป็นการแนะนำขั้นต้องการสั่งงานผ่าน PHP Curl โดยใช้วิธีการ "GET" บ้าง

ศึกษาการทำงานกัน
 $url = 'http://www.gps-vehicle.com/?'.$field_string; เป็นการตั้งค่า url ที่ต้องการจะส่งข้อมูลแบบ GET
 $curl = curl_init(); เป็นการกำหนดค่าเริ่มต้นสำหรับการใช้งานฟังก์ชั่น curl
 curl_setopt_array($curl, array( กำหนดอาเรย์สำหรับการส่งค่าพารามิเตอร์ต่างๆ ไปยังเซิร์ฟเวอร์
                        CURLOPT_RETURNTRANSFER => 1,  กำหนดออฟชั่นให้มีการส่งค่ากลับ
                        CURLOPT_URL => $url, กำหนดค่า Url ที่ใช้ในการทดลองส่งข้อมูล
                        CURLOPT_USERAGENT => 'Thai Prosperous IT co.,Ltd.'
                ));
 $resp = curl_exec($curl); สั่งให้ฟังก์ชั่น curl ประมวลผล โดยผลลัพธ์หรือค่าตอบกลับอยู่ในตัวแปร resp
 curl_close($curl); สั่งสิ้นสุดการทำงานของฟังก์ชั่น curl



 $url = 'http://www.gps-vehicle.com/?'.$field_string;
 echo $url;
 $curl = curl_init();
 curl_setopt_array($curl, array(
                        CURLOPT_RETURNTRANSFER => 1,
                        CURLOPT_URL => $url,
                        CURLOPT_USERAGENT => 'Thai Prosperous IT co.,Ltd.'
                   ));
 $resp = curl_exec($curl);
 curl_close($curl);


หลังจากนั้นก็ทดสอบการทำงานผ่านเทอร์มินอล โปรแกรมก็สามารถประมวลผลตามที่เราต้องการได้อย่างอัตโนมัติ ผู้เขียนตั้งค่าการทำงานผ่าน crond ทุกๆ 2 นาที หรือทำแบบ asynchronous ก็ได้ สำหรับฟังก์ชั่นการรับค่าจากอุปกรณ์ GPS TRACKER ให้ส่งต่อข้อมูลที่เปลี่ยนเป็นแบบวิธี GET ซึ่งรับประกันได้ว่าได้ผลการทำงานดีเช่นเดียวกัน ส่วนขนาดของข้อความสูงสุดที่รับได้ ผู้เขียนยังไม่ได้ทดสอบแต่ประเมินว่าขึ้นอยู่กับค่ามาตรฐานของโปรโตคอล HTTP อยู่แล้ว

วันอังคารที่ 19 กรกฎาคม พ.ศ. 2559

วุ่นวายกับการเปิดปิดไฟล์เพื่ออ่านและเขียนโดยภาษา PHP

ปวดหัวไปหลายวันทีเดียวสำหรับการเปิดปิดไฟล์เพื่ออ่านและเขียนโดยใช้โปรแกรมภาษา PHP  สำหรับโปรแกรมนี้ที่ผู้เขียนพัฒนาสำหรับอุปกรณ์ Thai GPSTRACKER รุ่นหนึ่งที่หากมีการรูดบัตรผ่านเครื่องอ่านใบอนุญาตขับรถ จะต้องนำข้อมูลรหัสบัตรไปเก็บที่ไฟล์ แต่ถ้านำบัตรใบนั้นไปรูดซ้ำให้ถือว่าเป็นการล็อกเอาท์ ส่วนหากรูดบัตรใหม่ถือว่าเป็นการเปลี่ยนบัตรให้ลบข้อมูลเดิมออกและนำข้อมูลบัตรใบใหม่จัดเก็บไว้แทน
โดยผู้เขียนสรุปการทำงานดังต่อไปนี้

1. หากไฟล์ยังไม่ถูกสร้างขึ้นมาให้ทำการเขียนใหม่ได้เลย
2. หากไฟล์มีข้อมูลอยู่แล้ว ให้อ่านข้อมูลเก่าขึ้นมาก่อน จากนั้นทำการเปรียบเทียบกับข้อมูลใหม่
2.1 หากข้อมูลใหม่กับข้อมูลเก่าเหมือนกันให้ทำการลบไฟล์เก่าออก
2.2 หากข้อมูลใหม่ต่างกันกับข้อมูลเก่าให้เขียนไฟล์ด้วยข้อมูลใหม่

ฟังดูจากโจทย์แล้วไม่น่ายากแต่พอได้ทำงานจริงพบว่า รันไทม์เออเรอ(runtime error) ตลอดเวลาหากเราไม่ทำการตรวจสอบข้อมูลดูก่อนว่ามีไฟล์ที่ต้องการเปิดอยู่จริง หรือไฟล์ที่มีอยู่กับไม่มีข้อมูลอยู่ในนั้นเลย ทำให้ฟังก์ชั่นการอ่านไฟล์ขึ้นมาเกิดข้อผิดพลาดได้

การดำเนินการข้อที่ 1 ตรวจสอบไฟล์เก่าดูก่อน หากยังไม่มีให้สร้างหรือเขียนไฟล์ใหม่
if ( file_exists("$imei")===false ) {
           $fh = fopen("$imei",'w+') or die('Cannot open file:');
           fwrite($fh,$newdriverid);
            fclose($fh);
}

การดำเนินการข้อที่ 2 หากไฟล์เก่ามีอยู่แล้ว ให้อ่านข้อมูลของไฟล์เก่า
 $fh = fopen("$imei",'r+') or die('Cannot open file:');
 $p_driverid = stream_get_contents($fh);
 fclose($fh);

การดำเนินการข้อที่ 2.1 ให้ทำการเปรียบเทียบข้อมูลเก่ากับข้อมูลใหม่ หากเหมือนกันให้ลบไฟล์เก่าออก
 if (strcmp($newdriverid,$p_driverid)==0) {
                 unlink("$imei");
 }
 

การดำเนินการข้อที่ 2.2  ส่วนหากข้อมูลต่างกันให้เขียนทับด้วยข้อมูลใหม่
$fh = fopen("$imei",'w+') or die('Cannot open file:');
fwrite($fh,$newdriverid);
fclose($fh);


                                      
สำหรับการนำไปพัฒนาต่อยอดก็สามารถดำเนินการได้เองโดยไม่ยาก โดยสาระสำคัญของบทความนี้ก็คือวิธีการเปิดไฟล์เพื่อเขียนทับ วิธีการเปิดไฟล์เพื่ออ่าน และวิธีการลบไฟล์ ทำยังไงให้ไม่เกิดข้อผิดพลาดและหยุดการทำงานของโปรแกรมนั่นเอง


วันพุธที่ 29 มิถุนายน พ.ศ. 2559

ทดลองส่งข้อความผ่านโปรโตคอล TCP โดยใช้คลาส php-socket-raw

ผู้เขียนเพิ่งจะมีโอกาสใช้งานโปรแกรม php มากขึ้นเรื่อยๆ เริ่มต้นจากการใช้งานเวบเซอร์วิส หลังจากนั้นก็เริ่มทำการส่งข้อมูลผ่านเครือข่าย udp หลังจากเสียเวลาศึกษาค้นคว้าหลายวันเพิ่งจะพบว่ามีคลาส php-socket-raw สามารถใช้งานได้อย่างง่ายดาย และมีเสถียรภาพสูง สำหรับหลายๆ คนที่ไม่เคยใช้งานมาก่อน มาวันนี้ลองไป ทดลองส่งข้อความผ่านโปรโตคอล TCP โดยใช้คลาส php-socket-raw กันเลย


ขั้นตอนที่ 1 ติดตั้งคลาส php-socket-raw โดยใช้คอมโพเซอร์

$composer require clue/socket-raw:~1.2

ขั้นตอนที่ 2 ทดลองคีย์โปรแกรมตามตัวอย่างเพื่อทดสอบการทำงาน

#!/usr/bin/env php
<?php

use Socket\Raw\Factory;

error_reporting(-1);

require_once __DIR__.'/vendor/autoload.php';

$factory = new Factory();
$socket = $factory->createClient('www.google.com:80');

echo 'Client connected to ' . $socket->getPeerName() . PHP_EOL . PHP_EOL;

$socket->write("GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n");

var_dump($socket->read(8192));

$socket->close();


3.ผลลัพธ์การรันโปรแกรม


root@sedonaVM:/var/www/tpit/ywt# php client-tcp.php
Client connected to 61.19.2.153:80

string(894) "HTTP/1.1 302 Found
Location: http://www.google.co.th/?gws_rd=cr&ei=sXhzV9qTPMr9vgTcyauIAQ
Cache-Control: private
Content-Type: text/html; charset=UTF-8
P3P: CP="This is not a P3P policy! See https://www.google.com/support/accounts/answer/151657?hl=en for more info."
Date: Wed, 29 Jun 2016 07:28:49 GMT
Server: gws
Content-Length: 261
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Set-Cookie: NID=81=pYSdoPTx0tkWQ9q2mQT6AAZra1NCPZd0t6DAkoOjl0_MYofhZ-y2wR1VKF5zzE_1aIZ6QNNFMu5HTbhhl7tRVgH14UcSkuJr9IMCIeHbPPeg94Vt1XXJLurt1pU8RIGm; expires=Thu, 29-Dec-2016 07:28:49 GMT; path=/; domain=.google.com; HttpOnly

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.co.th/?gws_rd=cr&amp;ei=sXhzV9qTPMr9vgTcyauIAQ">here</A>.
</BODY></HTML>
"
จากตัวอย่างจะเห็นได้ว่าเป็นการเรียกใช้งานคลาสและสร้างซ็อกเก็ต ซึ่งนับว่าจะช่วยลดขั้นตอนการพัฒนาโปรแกรมไปได้มาก สะดวกสบายต่อการนำไปใช้งานโดยเฉพาะ
คุณสมบัติของคลาสตามมาตรฐานการพัฒนาแบบออบเจค(oop) งานด้านการพัฒนาซอต์ฟแวร์ยังมีกันให้เห็นอยู่อีกมากมาย สิ่งสำคัญที่สุดโปรแกรมสคริป php มีฟีเจอร์เด่นไม่เป็นรองใคร

ต้องขอขอบพระคุณพื้นที่เวบบล็อกดี ๆจาก บจก. ไทย พรอสเพอรัส ไอที พร้อมกับขอฝากเวบไซต์ใหม่ gpstrackingthailand.com ไว้ด้วยสำหรับนำเสนอเรื่องราวสาระอันเป็นประโยขน์
ต่อการพัฒนาระบบจีพีเอสติดตามรถยนต์ เก็บเกี่ยวจากประสพการณ์จริงๆ

วันศุกร์ที่ 15 เมษายน พ.ศ. 2559

เปลี่ยนค่า repository ให้ Ubuntu Server 14.04 กัน

ห่างเหินการอัพเดทข้อมูลไปหลายวัน หลังจากที่ผู้เขียนกำลังอยู่ในช่วงการเชื่อมต่อข้อมูลเวบเซอร์วิสกับกรมการขนส่งทางบก เรื่องการส่งข้อมูลจากเซิร์ฟเวอร์ GPS ติดตามรถ สำหรับรายละเอียดทางเทคนิคของเวบเซอร์วิสก็เกริ่นคร่าว ๆว่าใช้วิธีการแลกเปลี่ยนแบบ Json XML ก็ผ่านพ้นไปได้ด้วยดี เซิร์ฟเวอร์ให้บริการเวบไซต์ของผู้เขียนเองก็ไม่ได้มีการอัพเดทซอฟต์แวร์ระบบปฏิบัติการมากว่า 7 เดือน คงต้องถึงเวลาเข้าไปดูแลกัน เริ่มต้นด้วยคำสั่งยอดนิยม apt-get update กลายเป็นว่าพบข้อผิดพลาดไม่สามารถทำการอัพเดทข้อมูลได้ ลองอยู่หลายวิธีไม่ว่าจะเข้าไปลบไฟล์เก่า ๆก่อนหรือทำการ  apt-get clean ก็ยังไม่หาย หาวิธีการอยู่นานจนได้พบว่าขั้นตอนที่ดีที่สุดก็คือเปลี่ยนค่า repository ใหม่ให้ชี้ไปที่ต้นฉบับ แล้วต้องทำยังไง

ผู้เขียนพบเวบไซต์หนึ่ง https://repogen.simplylinux.ch/generate.php สามารถกำหนดชื่อประเทศ ก็ออกรายชื่อของ repository lists ต่าง ๆของUbuntu Server ได้แล้ว ตามตัวอย่างที่ผู้เขียนใช้ลิงค์ข้างต้นสร้างให้

#------------------------------------------------------------------------------#
#                            OFFICIAL UBUNTU REPOS                             #
#------------------------------------------------------------------------------#


###### Ubuntu Main Repos
deb http://th.archive.ubuntu.com/ubuntu/ trusty main
deb-src http://th.archive.ubuntu.com/ubuntu/ trusty main

###### Ubuntu Update Repos
deb http://th.archive.ubuntu.com/ubuntu/ trusty-security main
deb http://th.archive.ubuntu.com/ubuntu/ trusty-updates main
deb-src http://th.archive.ubuntu.com/ubuntu/ trusty-security main
deb-src http://th.archive.ubuntu.com/ubuntu/ trusty-updates main



กลายเป็นว่าการค้นหา repository ไม่ใช่เป็นเรื่องยากอีกต่อไป หากบางครั้งมีงานด่วน ๆหลายงานเข้ามาแล้วเราต้องมาเสียเวลาค้นหา repository เพื่อทำการอัพเดทหรืออัพเกรดข้อมูลเซิร์ฟเวอร์ใหม่ ย่อมทำให้เสียโอกาสในการทำเรื่องอื่น ๆ

นอกจากนี้ เรายังสามารถสร้างให้สคริปข้างล่าง เพื่อทำการดึงข้อมูล repository ได้โดยตรง แต่มีข้อควรระวังคือไฟล์เดิม sources.list จะหายไปกลายเป็นไฟล์ใหม่แทนที่ ต้องระมัดระวังเรื่องเหล่านี้ให้ดี เพราะอาจจะทำให้เราต้องเสียเวลาไปอีกหลายนาทีได้เหมือนกัน
 Sources List
Direct Link to Sources List or use:
WARNING: This will overwrite your existing sources.list:
curl https://repogen.simplylinux.ch/txt/sources_60ab26885221b4e54eedf76af035715544e9e2cd.txt | sudo tee /etc/apt/sources.list
 
บทความในวันนี้ก็เป็นเทคนิคเล็ก ๆน้อย ๆที่เก็บมาฝากกันสำหรับแฟน ๆระบบปฏิบัติการลินุกส์ อูบันตู ทุก ๆท่าน ผู้เขียนเองพึงพาการใช้งานระบบซอต์ฟแวร์นี้มาจนถึงทุกวันนี้ ต้องขอขอบคุณมา ณ โอกาสนี้ด้วย

วันศุกร์ที่ 18 มีนาคม พ.ศ. 2559

ลองทดสอบเฟรมเวิร์ค bootstrap และ database class สำหรับใช้งาน php

การทดสอบเฟรมเวิร์คสำหรับใช้งานติดต่อกับโปรแกรมฐานข้อมูล Mysql ด้วยโปรแกรม PHP ในวันนี้ก็เพื่อที่จะทำให้สามารถบริหารจัดการข้อมูล select, insert, delete และ update ทำได้โดยง่ายที่สำคัญเป็นแบบออปเจค(oop) ป้องแฮกเกอร์โจมตีแบบสคริปได้เป็นอย่างดี

ส่วนเฟรมเวิร์ค bootstrap จะเป็นส่วนจัดการ css สำหรับการแสดงผลบนหน้าเวบเพจได้ทั้งแบบเดสท็อปและบนอุปกรณ์มือถือ นำไปต่อยอดพัฒนาในอนาคตได้เป็นอย่างดี ในครั้งนี้ผู้เขียนจะได้แนะนำคลาส crud สำหรับใช้ในการบริหารจัดการโปรแกรมฐานข้อมูลรวมถึงการเชื่อมต่อกับเฟรมเวิร์ค bootstrap ด้วย

ลองไปรู้จักคลาส crud กันก่อนประกอบไปด้วยฟังก์ชั่นต่อไปนี้

function __construct($DB_con) เป็นข้อกำหนดเริ่มต้นของการสร้างคลาส จะทำงานทุกครั้งอัตโนมัติเมื่อมีการสร้างออบเจคขึ้นใหม่ การกำหนดต้องเริ่มด้วย __ เครื่องหมายอันเดอร์สกอร์สองอัน
public function create($fname,$lname,$email,$contact) ฟังก์ชั่นสร้างออบเจคของตารางใหม่
public function getID($id) ฟังก์ชั่นหาค่าไอดีของตามราง
public function update($id,$fname,$lname,$email,$contact) ฟังก์ชั่นปรับปรุงค่าในตารางใหม่
public function delete($id) ฟังก์ชั่นการลบข้อมูลแบบ row
public function dataview($query) ฟังก์ชั่นการแสดงผลข้อมูลตามรูปแบบการค้นหา(query) โดยจะอาศัยเฟรมเวิร์ค bootstrap
public function paging($query,$records_per_page) เป็นฟังก์ชั่นเรียกการแสดงผลทีละหน้า
public function paginglink($query,$record_per_page)  เป็นฟังก์ชั่นสร้างลิงค์ของเพจในแต่ละหน้า

เพื่อไม่ให้เสียเวลาเราไปทดลองติดตั้งและทดสอบการใช้งานกันเลยดีกว่า

ขั้นตอนที่ 1 ให้ไปดาวน์โหลดซอร์สโค๊ดตามลิงค์ที่ผู้เขียนแปะไว้ให้นี้ จากนั้นแตกไฟล์ออกมาวางไว้ในตำแหน่งที่สามารถเรียกดูผ่านเวบไซต์ได้ http://www.codingcage.com/2015/04/php-pdo-crud-tutorial-using-oop-with.html



ขั้นตอนที่ 2 สร้างฐานข้อมูลตัวอย่างและกำหนดสิทธิ์การอนุญาตสำหรับการเข้าถึงฐานข้อมูลที่สร้างใหม่

CREATE TABLE IF NOT EXISTS `tbl_users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(25) NOT NULL,
  `last_name` varchar(25) NOT NULL,
  `email_id` varchar(50) NOT NULL,
  `contact_no` bigint(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=27 ;

--
-- Dumping data for table `tbl_users`
--

INSERT INTO `tbl_users` (`id`, `first_name`, `last_name`, `email_id`, `contact_no`) VALUES
(23, 'pradeep', 'khodke', 'pradeep@gmail.com', 9876543210),
(24, 'sohan', 'mahamune', 'sohan@gmail.com', 9874563210),
(25, 'john', 'doe', 'john@someone.com', 9778456123),
(26, 'test', 'test', 'test@test.com', 8745691230);

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

จากนั้นให้ทำการแก้ไขไฟล์ dbconfig.php เพื่อป้อนชื่อผู้ใช้ รหัสผ่าน และชื่อดาต้าเบสเพื่อให้คลาส crud สามารถเชื่อมต่อกับโปรแกรมฐานข้อมูลได้
ขั้นตอนที่ 3 ทดสอบการใช้งานหน้าแรกจะแสดงข้อมูลทั้งหมดที่อยู่ในฐานข้อมูลออกมา

ขั้นตอนที่ 4 ตัวอย่างหน้าจอการเพิ่มข้อมูลลงในฐานข้อมูล

ขั้นตอนที่ 5 ตัวอย่างหน้าจอการลบข้อมูล

รวบรัดตัดความจะพบว่าเพียงแค่ติดตั้งซอร์สโค๊ดเฟรมเวิร์ค bootstrap และ database class ง่ายๆ เพียงเท่านี้เราก็สามารถสร้างระบบบริหารจัดการโปรแกรมฐานข้อมูล MySql ได้อย่างดี การพัฒนาเป็นในรูปแบบออบเจคด้วย ไม่ต้องเสียเวลามากมายในการเขียนโค๊ด รวมถึงการหาวิธีการแสดงผล

ผู้เขียนตั้งใจจะนำไปพัฒนาต่อในส่วนของการสร้างระบบล็อกอิน รวมถึงนำไปใช้ในการบริหารจัดการบัญชีผู้ใช้งานในระบบฮอตสปอร์ตไวไฟ(radius)ในอนาคต แต่คงต้องอาศัยเวลาพัฒนาปรับปรุงไปเรื่อย ๆ แต่เนื้อหาที่น่าสนใจต่อไปก็คือการสร้างระบบล็อกอิน หากทดลองแล้วได้ผลดีประการใดก็จะได้นำมาบอกเล่ากันต่อไปในโอกาสข้างหน้า ผู้เขียนต้องขอขอบพระคุณ บจก. ไทย พรอสเพอรัส ไอที เอื้อเฟื้อพื้นที่เวบบล็อกดี ๆ มานำเสนอกัน และฝากประชาสัมพันธ์ความก้าวหน้าของทางบริษัทฯ ในการเชื่อมต่อระบบซอฟต์แวร์จีพีเอสติดตามรถกับกรมการขนส่งทางบกว่าขณะนี้ก้าวหน้าเกินกว่า 80% คาดว่า ภายในสิ้นเดือนเมษายน พ.ศ.2559 นี้ระบบการเชื่อมต่อพร้อมใบอนุญาตให้บริการจะเสร็จสิ้นสมบูรณ์



วันพุธที่ 2 ธันวาคม พ.ศ. 2558

ติดตั้ง Openvpn 2.3.2 บนโอเอส Ubuntu Desktop 14.04.3 LTS

หลังจากหายหน้าหายตาไปหลายสัปดาห์ ก็เป็นโอกาสอันดีอีกครั้งหนึ่งที่ผู้เ่ขียนได้เริ่มจับงานด้านการสร้างระบบเครือข่ายเสมือนส่วนตัว(virtual private network) สำหรับงานการทำ VPN นี้ตั้งใจจะนำมาทดสอบระบบกล้องวงจรปิดที่ต้องการรีโมตและบันทึกข้อมูลผ่านเครือข่ายที่มีความซับซ้อน ปัญหาหลักของกล้องวงจรปิดแบบไอพี (ip camera) ก็คือตัวเครื่องบันทึกข้อมูลสามารถรับสัญญาณภาพภายในเครือข่ายแลนเท่านั้นหากต้องการส่งข้ามเน็ตเวิร์คหรือผ่านอุปกรณ์ nat ย่อมไม่สามารถทำงานได้

ด้วยเหตุของความสลับซับซ้อนของระบบเครือข่ายโดยเฉพาะอย่างยิ่งหากต้องการดูภาพจากกล้องแบบเวลาจริงผ่านเครือข่ายมือถือแบบ 3G/4G ด้วยแล้วโอกาสที่จะทำงานได้ย่อมเป็นไปไม่ได้เลย ด้วยเหตุนี้การใช้งานเครือข่ายแบบเสมือนส่วนตัวน่าจะช่วยแก้ปัญหาในเรื่องนี้ได้ แต่ข้อนี้ผู้เขียนยังไม่เคยได้ทดสอบ เพื่อป้องกันการสับสนวันนี้เรามาสร้างเครื่องเซิร์ฟเวอร์หรือเครื่องลูกข่ายสำหรับใช้งานโปรแกรม openvpn กัน

ขั้นตอนที่ 1 ดำเนินการติดตั้งโปรแกรม openvpn และโปรแกรมสร้างคีย์สาธารณะ easy-rsa
#apt-get install openvpn easy-rsa

ขั้นตอนที่ 2 หลังจากติดตั้งโปรแกรมเสร็จสิ้นสมบูรณ์ตามขั้นตอนที่ 1 แล้วให้แก้ไขไฟล์ vars อยู่ในโฟลเดอร์ /etc/openvpn/easy-rsa
export KEY_COUNTRY="TH"
export KEY_PROVINCE="Nonthaburi"
export KEY_CITY="Saima"
export KEY_ORG="Thai Prosperous IT Co.,Ltd."
export KEY_EMAIL="             @gmail.com"

ขั้นตอนที่ 3 จากนั้นให้ดำเนินการตามขั้นตอนต่อไปนี้ source vars เป็นการบอกสคริปให้รู้จักตัวแปรที่ได้แก้ไขใหม่ ส่วน clean-all เป็นการลบค่าเก่าของโฟลเดอร์ keys
#source vars
#./clean-all

ขั้นตอนที่ 4 เป็นการสร้าง Certificate Authority(CA) หรือคีย์หลักในการให้ใบรับรองดิจิตอล
#./build-ca

Generating a 2048 bit RSA private key
....................................................................................................+++
......................................................................+++
writing new private key to 'ca.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [TH]:
State or Province Name (full name) [NONTHABURI]:
Locality Name (eg, city) [SAIMA]:
Organization Name (eg, company) [OpenVpn IP Camera Server]:
Organizational Unit Name (eg, section) [OpenVpnDevelopmentUnit]:
Common Name (eg, your name or your server's hostname) [OpenVpn IP Camera Server CA]:
Name [EasyRSA]:
Email Address [me@myhost.mydomain]:             @gmail.com

ขั้นตอนที่ 5 จากนั้นสร้าง Public Keys สำหรับเครื่องเซิร์ฟเวอร์
# ./build-key-server OpenVpnServer
# ./build-dh

ขั้นตอนที่ 6 ให้ทำการคัดลอกคีย์ต่อไปนี้ไปยังโฟลเดอร์ /etc/openvpn
#cd keys/
#cp myservername.crt myservername.key ca.crt dh2048.pem /etc/openvpn/

ขั้นตอนที่ 7 สำหรับเครื่องเซิร์ฟเวอร์ที่ต้องการสร้างเราเตอร์จากอินเตอร์เฟส Tunnel ไปยังเครือข่ายอื่นในระบบให้แก้ไขไฟล์ /etc/sysctl.conf เพื่อทำการฟอร์เวิร์ดไอพี

net.ipv4.ip_forward=1

เป็นอันสิ้นสุดการติดตั้ง Openvpn 2.3.2 บนโอเอส Ubuntu Desktop 14.04.3 LTS สำหรับไฟล์ server.conf คอนฟิกตัวอย่างสำหรับ server สามารถคัดลอกมาได้จากโฟลเดอร์ /usr/share/doc/openvpn/examples/sample-config-files/

สำหรับการดำเนินการติดตั้ง Openvpn นั้นสามารถทำได้โดยไม่ยุ่งยาก ส่วนการนำไปใช้งานนั้นต้องค่อยๆ เรียนรู้และศึกษากันไป หากผู้เขียนได้ทดลองได้ผลประการใดจะรีบนำเสนอทันที การนำไปประยุกต์ใช้งานนั้นค่อนข้างกว้างขวาง หากลองสังเกตดีๆ มือถือแอนดอร์ยเองก็มีแอพพลิเคชั้นประเภทนี้ให้ลองใช้งานกันอย่างมากมายทีเดียว

สำหรับเนื้อหาในวันนี้ต้องขอขอบพระคุณ บจก.ไทย พรอสเพอรัส ไอที ผู้นำด้านการให้บริการระบบ GPS TRACKING ครบวงจรด้วยอุปกรณ์ชั้นนำนำเข้าจากยุโรปโดยตรง พร้อมระบบจีพีเอสเซิร์ฟเวอร์ออนไลน์ใช้งานได้ในประเทศไทย ไม่ต้องเปลืองทราฟฟิกไปยังต่างประเทศ

วันอาทิตย์ที่ 19 กรกฎาคม พ.ศ. 2558

เมื่อต้องสู้กับ สแปมเมลล์ บนซอฟต์แวร์ Zimbra Community 8.0.1.GA.5438

ยินดีต้อนรับสู่เวบบล็อกดีๆ ของคนรักโอเพ่นซอร์ส หลังจากไม่ได้อัพเดทมาหลายสัปดาห์ ผู้เขียนเองพักหลังก็ไม่ค่อยได้มีงานเกี่ยวกับด้านการดูแลระบบให้ได้แก้ไขมากนัก เพราะปัจจุบันงานที่ทำมุ่งเน้นไปยังธุรกิจ GPS TRACKER เป็นหลัก แต่อย่างไรก็แล้วแต่หากมีงานด้านการดูแลระบบเข้ามาให้แก้ไข ก็จะได้อัพเดทเรื่องราวดีๆ เหล่านี้ให้ได้ทราบกัน

เมื่อเดือนที่ผ่านมาปรากฏว่าเครื่อง Zimbra Community 8.0.1.GA.5438 ที่ผู้เขียนดูแลอยู่เป็นสแปม ไอพีติดแบล็กลิสต์ ในช่วงเวลาที่ผ่านมา 1 เดือนได้พยายามแจ้งไปยังเวบไซต์ต่างๆที่รายงานด้านสแปม จนสามารถปลดล็อกไอพีได้ แต่เซิร์ฟเวอร์เมลล์ของผู้เขียนก็ยังไม่สามารถส่งข้อความไปยังโดเมนในกลุ่มค่ายไมโครซอฟต์ได้ เช่น hotmail.com live.com และ msn.com จึงเป็นที่มา "เมื่อต้องสู้กับ สแปมเมลล์ บนซอฟต์แวร์ Zimbra Community 8.0.1.GA.5438"

ผู้เขียนมีการตั้งระบบป้องกันเบื้องต้นอยู่แล้วนั่นก็คือ fail2ban โดยใช้คอนฟิกดีฟอลต์พวก postfix และ sasl ซึ่งมันไม่ได้ผล เครื่องเมลล์เซิร์ฟเวอร์โดนโจมตีและไอพีติดแบล็คลิสต์เป็นประจำ จากการค้นคว้าไปตามเวบไซต์ต่างๆ มีการพูดถึงการป้องกันสแปมโดยใช้ fail2ban อยู่บ้างแต่เป็นแบบสั้นๆ ครั้งนี้ผู้เขียนก็ได้ยึดตามและทดลองได้ผลดี ผ่านมาสองสัปดาห์ยังไม่มีสแปมเมลล์เกิดขึ้นในระบบ ก็ลองใช้วิธีนี้ดูก่อนหากระบบเมลล์เซิร์ฟเวอร์ที่เราดูแลอยู่พบเจอปัญหาสแปมเมลล์ข้างต้น

ขั้นตอนที่ 1 โดยขั้นตอนการกำหนดค่าให้กับคอนฟิกของ fail2ban สามารถดำเนินการได้ดังนี้ ให้ทำการแก้ไขไฟล์ jail.conf


[zimbra-account]
enabled = true
filter = zimbra
action = iptables-allports[name=zimbra-account]
sendmail[name=zimbra-account, dest=admin@example.com]
logpath = /opt/zimbra/log/mailbox.log
bantime = 600
maxretry = 2

[zimbra-audit]
enabled = true
filter = zimbra
action = iptables-allports[name=zimbra-audit]
sendmail[name=Zimbra-audit, dest=admin@example.com]
logpath = /opt/zimbra/log/audit.log
bantime = 600
maxretry = 2

[zimbra-recipient]
enabled = true
filter = zimbra
action = iptables-allports[name=zimbra-recipient]
sendmail[name=Zimbra-recipient, dest=admin@example.com]
logpath = /var/log/zimbra.log
#findtime = 604800
bantime = 172800
maxretry = 2

[postfix]
enabled = true
filter = postfix
action = iptables-multiport[name=postfix, port=smtp, protocol=tcp]
sendmail-buffered[name=Postfix, dest=admin@example.com]
logpath = /var/log/zimbra.log
bantime = -1
maxretry = 5

ขั้นตอนที่ 2 จากนั้นให้ทำการสร้างไฟล์ zimbra.conf ในโฟลเดอร์ /etc/fail2ban/filter.d/
# Fail2Ban configuration file
#
# Author:
#
# $Revision: 1 $
#

[Definition]

# Option:  failregex
# Notes.:  regex to match the password failures messages in the logfile. The
#          host must be matched by a group named "host". The tag "<HOST>" can
#          be used for standard IP/hostname matching and is only an alias for
#          (?:::f{4,6}:)?(?P<host>[\w\-.^_]+)
# Values:  TEXT
#
failregex = \[ip=<HOST>;\] account - authentication failed for .* \(no such acco
unt\)$
                        \[ip=<HOST>;\] security - cmd=Auth; .* error=authenticat
ion failed for .*, invalid password;$
                        ;oip=<HOST>;.* security - cmd=Auth; .* protocol=soap; er
ror=authentication failed for .* invalid password;$
                        \[oip=<HOST>;.* SoapEngine - handler exception: authenti
cation failed for .*, account not found$
                        WARN .*;ip=<HOST>;ua=ZimbraWebClient .* security - cmd=A
dminAuth; .* error=authentication failed for .*;$
                        NOQUEUE: reject: RCPT from .*\[<HOST>\]: 550 5.1.1 .*: R
ecipient address rejected:

# .*\[ip=<HOST>;\] .* - authentication failed for .* \(invalid password\)
#
# Option:  ignoreregex
# Notes.:  regex to ignore. If this regex matches, the line is ignored.
# Values:  TEXT
#
ignoreregex =
root@teltonika:/etc/fail2ban/filter.d# more zimbra.conf
# Fail2Ban configuration file
#
# Author:
#
# $Revision: 1 $
#

[Definition]

# Option:  failregex
# Notes.:  regex to match the password failures messages in the logfile. The
#          host must be matched by a group named "host". The tag "<HOST>" can
#          be used for standard IP/hostname matching and is only an alias for
#          (?:::f{4,6}:)?(?P<host>[\w\-.^_]+)
# Values:  TEXT
#
failregex = \[ip=<HOST>;\] account - authentication failed for .* \(no such account\)$
                        \[ip=<HOST>;\] security - cmd=Auth; .* error=authentication failed for .*, invalid password;$
                        ;oip=<HOST>;.* security - cmd=Auth; .* protocol=soap; error=authentication failed for .* invalid password;$
                        \[oip=<HOST>;.* SoapEngine - handler exception: authentication failed for .*, account not found$
                        WARN .*;ip=<HOST>;ua=ZimbraWebClient .* security - cmd=AdminAuth; .* error=authentication failed for .*;$
                        NOQUEUE: reject: RCPT from .*\[<HOST>\]: 550 5.1.1 .*: Recipient address rejected:

# .*\[ip=<HOST>;\] .* - authentication failed for .* \(invalid password\)
#
# Option:  ignoreregex
# Notes.:  regex to ignore. If this regex matches, the line is ignored.
# Values:  TEXT
#
ignoreregex =





ขั้นตอนที่ 3 ให้สั่งเริ่มต้นการทำงานเซอร์วิส fail2ban ใหม่

#/etc/init.d/fail2ban restart

ขั้นตอนที่ 4 ให้ทดสอบการตรวจสอบดูว่าเราสร้างไฟล์ข้างต้นถูกต้องสมบูรณ์หรือไม่ พร้อมกับทดสอบการป้องกันดูว่าจะได้ผลหรือไม่

# fail2ban-regex /var/log/zimbra.log /etc/fail2ban/filter.d/zimbra.conf

Running tests
=============

Use regex file : /etc/fail2ban/filter.d/zimbra.conf
Use log file   : /var/log/zimbra.log


Results
=======

Failregex
|- Regular expressions:
|  [1] \[ip=<HOST>;\] account - authentication failed for .* \(no such account\)$
|  [2] \[ip=<HOST>;\] security - cmd=Auth; .* error=authentication failed for .*, invalid password;$
|  [3] ;oip=<HOST>;.* security - cmd=Auth; .* protocol=soap; error=authentication failed for .* invalid password;$
|  [4] \[oip=<HOST>;.* SoapEngine - handler exception: authentication failed for .*, account not found$
|  [5] WARN .*;ip=<HOST>;ua=ZimbraWebClient .* security - cmd=AdminAuth; .* error=authentication failed for .*;$
|  [6] NOQUEUE: reject: RCPT from .*\[<HOST>\]: 550 5.1.1 .*: Recipient address rejected:
|
`- Number of matches:
   [1] 0 match(es)
   [2] 0 match(es)
   [3] 0 match(es)
   [4] 0 match(es)
   [5] 0 match(es)
   [6] 1 match(es)

Ignoreregex
|- Regular expressions:
|
`- Number of matches:

Summary
=======

Addresses found:
[1]
[2]
[3]
[4]
[5]
[6]
    66.196.81.146 (Sun Jul 19 09:32:37 2015)

Date template hits:
225061 hit(s): MONTH Day Hour:Minute:Second
0 hit(s): WEEKDAY MONTH Day Hour:Minute:Second Year
0 hit(s): WEEKDAY MONTH Day Hour:Minute:Second
0 hit(s): Year/Month/Day Hour:Minute:Second
0 hit(s): Day/Month/Year Hour:Minute:Second
0 hit(s): Day/Month/Year Hour:Minute:Second
0 hit(s): Day/MONTH/Year:Hour:Minute:Second
0 hit(s): Month/Day/Year:Hour:Minute:Second
0 hit(s): Year-Month-Day Hour:Minute:Second
0 hit(s): Year.Month.Day Hour:Minute:Second
0 hit(s): Day-MONTH-Year Hour:Minute:Second[.Millisecond]
0 hit(s): Day-Month-Year Hour:Minute:Second
0 hit(s): TAI64N
0 hit(s): Epoch
0 hit(s): ISO 8601
0 hit(s): Hour:Minute:Second
0 hit(s): <Month/Day/Year@Hour:Minute:Second>

Success, the total number of match is 1

However, look at the above section 'Running tests' which could contain important
information.

จากตัวอย่างจะพบว่ามีการตรวจสอบพบไอพีที่ผิดกฏข้อที่ 6  "NOQUEUE: reject: RCPT from .*\[<HOST>\]: 550 5.1.1 .*: Recipient address rejected:" ซึ่งหากไอพีนี้กระทำซ้ำกันเพียง 2 ครั้งเซิร์ฟเวอร์ก็จะทำการแบบไอพีนี้ทันทีอย่างน้อย 1 ชั่วโมง