分类 linux 下的文章

linux下使用TCP和UDP协议同步时间

一.相关协议

时间是系统最基本也是最重要的部分之一,系统中的文件读写、传输等都是以系统时间为准,很多业务也要求服务器的系统时间保持一致,这就需要使用时间同步服务。目前主要有两种协议提供了时间同步服务:

  1. NTP/SNTP协议(RFC1305): 基于udp协议(123端口),可以估算数据包在网络上的延迟和计算机时间偏差,提供毫秒级的精度,是目前网络时间服务器使用的主流协议
  2. TIME协议 (RFC868) : 该协议比较简单,使用tcp/udp的37端口,服务会返回从1900年1月1日午夜到现在的秒数,精度低,使用较少

二.软件支持和应用场景

本文只介绍linux下软件支持:

  1. NTP协议 : ntpdate/ntp(d)
  2. TIME协议: rdate
  3. 手动同步 : date

使用那种软件同步时间要看应用的场景:

  1. 对时间要求不高时使用手动同步或者ntpdate+cronjob来同步时间即可
  2. 如果业务对时间非常敏感,不允许时间跃变,可以用ntpd平滑同步
  3. 在一些有防护的机房,默认丢弃所有进出的udp包,导致ntpdate/ntpd无法同步时间,这时就需要用TCP协议来同步时间

三.配置时间同步

3.1 ntpdate使用

ntpdate会马上更改时间,使用比较简单,安装ntpdate:

yum install ntpdate

只查询不同步时间:

ntpdate -q time.windows.com

同步时间:

ntpdate time.windows.com

可以配合crontab每天执行一次同步:

  1  5  *  *  * root /usr/sbin/ntpdate time.windows.com

如果同步出错,可以使用debug模式排查问题:

ntpdate -d time.windows.com

3.2 ntp使用

安装:


yum install ntp

贴一份ntp.conf配置,少量修改即可:

driftfile /var/lib/ntp/drift
restrict default kod nomodify notrap nopeer noquery
restrict -6 default kod nomodify notrap nopeer noquery

#允许 loopback的所有访问
restrict 127.0.0.1 
restrict -6 ::1

# 允许的局域网络段或ip
#restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap
restrict 10.0.0.0 mask 255.0.0.0 nomodify motrap
restrict 192.0.0.0 mask 255.0.0.0 nomodify motrap

#允许上层时间服务器修改本地时间
    restrict 0.centos.pool.ntp.org nomodify notrap noquery
restrict 1.centos.pool.ntp.org nomodify notrap noquery
restrict 2.centos.pool.ntp.org nomodify notrap noquery
restrict 3.centos.pool.ntp.org nomodify notrap noquery

# 公共NTP服务器,可以去http://www.pool.ntp.org找    
server 0.centos.pool.ntp.org perfer
server 1.centos.pool.ntp.org 
server 2.centos.pool.ntp.org 
server 3.centos.pool.ntp.org 

# 外部时间服务器不可用时,以本地时间作为时间服务
server  192.168.56.101     
fudge   192.168.56.101  stratum 10

includefile /etc/ntp/crypto/pw
keys /etc/ntp/keys

因为ntp会平滑的同步时间,如果本地时间和服务器时间相差太大,会导致非常久才会同步时间,或者根本不会平滑同步。所以建议使用ntp同步之前先ntpdate同步一下,不同步也可以,按照上面的配置,第一次启动时会自动同步时间。配置好就可以作为时间服务器为其他服务器提供时间同步服务

查看时间同步状态:

ntpstat

查看与上层服务器的连接状态:

ntpq -p

3.3 rdate 同步时间

ntpdate和ntp都只能用udp来同步时间,rdate支持用tcp或者udp同步时间,安装rdate:

yum install rdate

网上支持time协议的服务器不多,查看服务器返回时间:

rdate -p time.nist.gov

或者:


 nc time.nist.gov 13

使用tcp同步时间:

rdate -s time.nist.gov

使用udp同步时间:

rdate -u time.nist.gov

其他rdate服务器可以在http://tf.nist.gov/tf-cgi/servers.cgi 查看

3.4 手动同步时间

使用date命令手动同步,用法:

date -s  10:23:10
date -s 'Thu, 17 Dec 2015 10:23:10 GMT'

这种方法精度太差,可以借助网站的http头同步时间,我们先来看一下,http头的格式:

curl -s --head http://www.nixops.me

返回为:

HTTP/1.1 200 OK
Date: Thu, 17 Dec 2015 10:23:30 GMT
Server: Mod_Security 2.5.9 enabled
X-Powered-By: PHP/5.3.29
X-Pingback: http://www.nixops.me/action/xmlrpc
Vary: Accept-Encoding,User-Agent
Content-Type: text/html; charset=UTF-8

只要过滤出DATE中的时间即可,命令如下:

curl -s --head http://www.nixops.me | grep ^Date: | sed 's/Date: //g'

返回为:

Thu, 17 Dec 2015 10:26:13 GMT 

这个格式date命令就能用了,和date命令整合一下,查询时间:

date -d "$(curl -s --head http://www.nixops.me | grep ^Date: | sed 's/Date: //g')"

设置时间:

date -s "$(curl -s --head http://www.nixops.me | grep ^Date: | sed 's/Date: //g')"

当然我的服务器时间不够精确,你可以把 www.nixops.me 换成 google.com或者baidu.com,这样就可以保证时间的精度了。总的来说:tcp和手动同步的方式要建立连接,又没有误差计算,所以精度不如用ntp,这也是ntp流行的原因

3.5 写入硬件时间

linux的时间分为系统时间和硬件时间两种,以上各种方法同步的都是系统时间,服务器启动时会从硬件(BIOS)读取时间作为系统时间,所以也要同步一下硬件时间。
查看硬件时间:

hwclock -r 

对比下系统时间和硬件时间:

hwclock -r && date 

将系统时间写入硬件时间:

hwclock -w

参考文章:
http://blog.csdn.net/cymm_liu/article/details/10932181
http://linux.vbird.org/linux_server/0440ntp.php
http://superuser.com/questions/635020/how-to-know-current-time-from-internet-from-command-line-in-linux

SSD vps优化之swap

linux在内存不足的时候会用到swap,对于内存有限的vps,swap尤其重要,如果vps硬盘是读写速度快的SSD,相对于机械硬盘的来说,性能提升还是很大的。部分vps厂商如:digitalocean,默认关闭了swap,会导致部分要求系统有swap的软件,如mysql无法成功启动。同时为了“增大内存”并提升系统,也要开启swap。

swap可以是磁盘分区,也可以是文件,之前写过一篇使用lvm时调整swap分区的文章:kali调整swap分区
没有用lvm时增加swap文件就非常简单了,检查swap状态:

swapon -s  或者free -m

创建swap文件:

dd if=/dev/zero of=/opt/swapfile bs=1024 count=512k

会在/opt/下创建一个512M的swap文件,大小按需调整。
创建虚拟内存:

mkswap /opt/swapfile

启用swap文件:

swapon /opt/swapfile

开机挂载swap文件:

vim /etc/fstab

加入:


/opt/swapfile          swap            swap    defaults        0 0

修改权限,只允许root读写:

chown root.root /opt/swapfile
chmod 0600 /opt/swapfile

当内存还有很多空余时使用swap会影响性能,所以要调整swap分区的使用频率:

cat /proc/sys/vm/swappiness

swappiness值是从0到100,代表内核的使用频率,默认是60。可以通过sysctl来调整:

vim /etc/sysctl.conf

加入:

 vm.swappiness=10

使配置生效:

sysctl -p

参考文章:
https://www.digitalocean.com/community/tutorials/how-to-add-swap-on-centos-6

XtraBackup全量和增量备份shell脚本

生产上的mysql要做数据备份,使用Percona XtraBackup进行热备份,本来想偷懒去网上找一个,找来找去没找到太合适的,自己写了个Percona XtraBackup的全备份和增量备份shell脚本,用法:

全备份: ./backup.sh full
增量备份: ./backup.sh inc

配合crond job 执行,很方便
脚本内容:

#!/bin/sh
#percona-xtrabackup全量和增量备份脚本
#Author :Will
#WebSite : www.nixops.me
#date : 2015/10/21
#usage: 1. full backup  : ./backup.sh full
#       2. incremental backup : ./backup.sh inc 


Innobackupex_Path=/usr/bin/innobackupex
Mysql_Client=/usr/bin/mysql
Bak_Time=`date +%Y%m%d_%H%M%S`

#请勿在Incrbackup_Path及下属文件夹创建或写入内容,否则可能导致增量备份不成功
Backup_Dir=/opt/backup   #备份主目录
    #Backup_Dir=/opt/backup/data/`data -I`   #按日期生成备份主目录
Fullbackup_Path=$Backup_Dir/full # 全库备份的目录  
Incrbackup_Path=$Backup_Dir/incr # 增量备份的目录  
Log_Path=$Backup_Dir/logs   #日志文件目录
Keep_Fullbackup=5    #保留的全备份数量,此处要加1; 如要保留2个,此处要写3 
Mysql_Conf=/etc/my.cnf #mysql配置文件
Mysql_Opts='--socket=/opt/mysql/mysql.sock  --host=localhost --user=root --password=9hb1a$OCinbl'  #mysql的连接配置,按需修改


Error()  
  {  
    echo -e "\e[1;31m$1\e[0m" 1>&2
    exit 1  
  }  
 
Backup()
  {
    #两个参数为全量备份,第一个参数为备份目录,第二个参数为日志全路径
    if [ $# = 2 ] ; then
        $Innobackupex_Path --defaults-file=$Mysql_Conf $Mysql_Opts  --no-timestamp  $1/full_$Bak_Time>$2 2>&1
    #三个参数为增量备份,第一个为增量备份目录,第二个为上个增量备份目录,第三个为日志全路径 
    elif [ $# = 3 ];then
        $Innobackupex_Path --defaults-file=$Mysql_Conf $Mysql_Opts  --no-timestamp --incremental  $1/incr_$Bak_Time  --incremental-basedir $2 >$3 2>&1
    else
    Error "Backup(): 参数不正确"
     fi 
  } 


#获得某个目录下,最近修改的目录
Lastest_Dir()
  {
    if [ -d $1 ]; then
        path=`ls -t $1 |head -n 1`
        if [  $path ]; then
            echo $path
        else
            Error "Lastest_Diri(): 目录为空,没有最新目录"
        fi
    else
        Error "Latest_Dir(): 目录不存在或者不是目录"
    fi
  }

 
#进行增量备份
Do_Inc()
  {
    if [ "$(ls -A $Incrbackup_Path)" ] ; then
        #不是第一次增量备份,以最新的增量备份目录为base_dir
        Backup $Incrbackup_Path $Incrbackup_Path/`Lastest_Dir $Incrbackup_Path`  $Log_Path/incr_$Bak_Time.log 
      else
        #第一次增量备份要先全量备份
        Backup $Incrbackup_Path  $Log_Path/incr_full_$Bak_Time.log 
    fi
  }

#进行全量备份
Do_Full()
  {
    Backup     $Fullbackup_Path $Log_Path/full_$Bak_Time.log
    cd $Fullbackup_Path 
    ls -t |tail -n +$Keep_Fullbackup |xargs  rm -rf 
    
  }

#环境和配置检查
Check()
  {
    #检查目录和创建目录
    if [ ! -d $Fullbackup_Path ];then
        mkdir -p $Fullbackup_Path
    fi

    if [ ! -d $Incrbackup_Path ];then
        mkdir -p $Incrbackup_Path
    fi

    if [ ! -d $Log_Path ];then
        mkdir -p $Log_Path
    fi

    #检测所需的软件
    if [ ! -f $Innobackupex_Path ];then
        Error "未安装xtradbbackup或xtradbbackup路径不正确"
    fi

    if [ ! -f $Mysql_Client ];then
        Error "未安装mysql客户端"
    fi
    
    if [ ! -f $Mysql_Conf ];then
        Error "mysql配置文件路径不正确"
    fi

    #检查mysql的运行状态
    if [ `netstat -tlnp |grep mysqld |wc -l` = 0 ];then
        Error "MySQL没有运行"
    fi

    #验证mysql的用户和密码是否正确
    if  ! `echo 'exit' | $Mysql_Client -s  $Mysql_Opts >/dev/null 2>&1` ; then
        Error "提供的数据库连接配置不正确!"  
    fi
  }

case $1 in

       full)
          Check
          Do_Full
          ;;

        inc)
          Check
          Do_Inc
          ;;

         *)
          echo "full 全量备份"
      echo "inc  增量备份"
      ;;
esac    

nginx防止DDOS攻击配置(2)

nginx防止DDOS攻击配置(2)

第一篇: https://opswill.com/articles/nginx-anti-ddos-setting.html

我们用的高防服务器只防流量攻击不防CC,现在的攻击多数都是混合型的,而且CC攻击很多,防CC只能自己搞了,按照第一篇的配置,在实际的使用中效果并不理想。限制每秒钟的请求数和ip连接数,属于杀敌一千自损八百的做法。是可以防小规模的cc攻击,但是不够灵活,限制严了,误杀率很大;限制少了,当攻击的ip量达到一定规模的时候,传递到后端的请求还是非常多,导致php撑不住挂掉。这里在上一篇的基础上详细介绍一下我在生产中使用的配置。

1.修改最大连接数

最大连接数不够的话,nginx日志中会出现"Too many open files"错误。系统默认的1024太小了,在/etc/security/limits.conf中增加:

* soft nproc 65535
* hard nproc 65535
* soft nofile 65535
* hard nofile 65535

2.sysctl优化

这个比较考验内功,暂时还没太多研究,从网上搬运了一份,以后在慢慢学习:

###
### GENERAL SYSTEM SECURITY OPTIONS ###
###

# Controls the System Request debugging functionality of the kernel
kernel.sysrq = 0

# Controls whether core dumps will append the PID to the core filename.
# Useful for debugging multi-threaded applications.
kernel.core_uses_pid = 1

#Allow for more PIDs
kernel.pid_max = 65535

# The contents of /proc/<pid>/maps and smaps files are only visible to
# readers that are allowed to ptrace() the process
kernel.maps_protect = 1

#Enable ExecShield protection
kernel.exec-shield = 1
kernel.randomize_va_space = 2

# Controls the maximum size of a message, in bytes
kernel.msgmnb = 65535

# Controls the default maxmimum size of a mesage queue
kernel.msgmax = 65535

# Restrict core dumps
fs.suid_dumpable = 0

# Hide exposed kernel pointers
kernel.kptr_restrict = 1

###
### IMPROVE SYSTEM MEMORY MANAGEMENT ###
###

# Increase size of file handles and inode cache
fs.file-max = 209708

# Do less swapping
vm.swappiness = 30
vm.dirty_ratio = 30
vm.dirty_background_ratio = 5

# specifies the minimum virtual address that a process is allowed to mmap
vm.mmap_min_addr = 4096

# 50% overcommitment of available memory
vm.overcommit_ratio = 50
vm.overcommit_memory = 0

# Set maximum amount of memory allocated to shm to 256MB
kernel.shmmax = 268435456
kernel.shmall = 268435456

# Keep at least 64MB of free RAM space available
vm.min_free_kbytes = 65535

###
### GENERAL NETWORK SECURITY OPTIONS ###
###

#Prevent SYN attack, enable SYNcookies (they will kick-in when the max_syn_backlog reached)
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_max_syn_backlog = 4096

# Disables packet forwarding
net.ipv4.ip_forward = 0
net.ipv4.conf.all.forwarding = 0
net.ipv4.conf.default.forwarding = 0
net.ipv6.conf.all.forwarding = 0
net.ipv6.conf.default.forwarding = 0

# Disables IP source routing
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0

# Enable IP spoofing protection, turn on source route verification
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Disable ICMP Redirect Acceptance
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0

# Enable Log Spoofed Packets, Source Routed Packets, Redirect Packets
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

# Decrease the time default value for tcp_fin_timeout connection
net.ipv4.tcp_fin_timeout = 7

# Decrease the time default value for connections to keep alive
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_intvl = 15

# Don't relay bootp
net.ipv4.conf.all.bootp_relay = 0

# Don't proxy arp for anyone
net.ipv4.conf.all.proxy_arp = 0

# Turn on the tcp_timestamps, accurate timestamp make TCP congestion control algorithms work better
net.ipv4.tcp_timestamps = 1

# Don't ignore directed pings
net.ipv4.icmp_echo_ignore_all = 0

# Enable ignoring broadcasts request
net.ipv4.icmp_echo_ignore_broadcasts = 1

# Enable bad error message Protection
net.ipv4.icmp_ignore_bogus_error_responses = 1

# Allowed local port range
net.ipv4.ip_local_port_range = 16384 65535

# Enable a fix for RFC1337 - time-wait assassination hazards in TCP
net.ipv4.tcp_rfc1337 = 1

# Do not auto-configure IPv6
net.ipv6.conf.all.autoconf=0
net.ipv6.conf.all.accept_ra=0
net.ipv6.conf.default.autoconf=0
net.ipv6.conf.default.accept_ra=0
net.ipv6.conf.eth0.autoconf=0
net.ipv6.conf.eth0.accept_ra=0

###
### TUNING NETWORK PERFORMANCE ###
###

# For high-bandwidth low-latency networks, use 'htcp' congestion control
# Do a 'modprobe tcp_htcp' first
net.ipv4.tcp_congestion_control = htcp

# For servers with tcp-heavy workloads, enable 'fq' queue management scheduler (kernel > 3.12)
net.core.default_qdisc = fq

# Turn on the tcp_window_scaling
net.ipv4.tcp_window_scaling = 1

# Increase the read-buffer space allocatable
net.ipv4.tcp_rmem = 8192 87380 16777216
net.ipv4.udp_rmem_min = 16384
net.core.rmem_default = 262144
net.core.rmem_max = 16777216

# Increase the write-buffer-space allocatable
net.ipv4.tcp_wmem = 8192 65536 16777216
net.ipv4.udp_wmem_min = 16384
net.core.wmem_default = 262144
net.core.wmem_max = 16777216

# Increase number of incoming connections
net.core.somaxconn = 32768

# Increase number of incoming connections backlog
net.core.netdev_max_backlog = 16384
net.core.dev_weight = 64

# Increase the maximum amount of option memory buffers
net.core.optmem_max = 65535

# Increase the tcp-time-wait buckets pool size to prevent simple DOS attacks
net.ipv4.tcp_max_tw_buckets = 1440000

# try to reuse time-wait connections, but don't recycle them (recycle can break clients behind NAT)
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_tw_reuse = 1

# Limit number of orphans, each orphan can eat up to 16M (max wmem) of unswappable memory
net.ipv4.tcp_max_orphans = 16384
net.ipv4.tcp_orphan_retries = 0

# Increase the maximum memory used to reassemble IP fragments
net.ipv4.ipfrag_high_thresh = 512000
net.ipv4.ipfrag_low_thresh = 446464

# don't cache ssthresh from previous connection
net.ipv4.tcp_no_metrics_save = 1
net.ipv4.tcp_moderate_rcvbuf = 1

# Increase size of RPC datagram queue length
net.unix.max_dgram_qlen = 50

# Don't allow the arp table to become bigger than this
net.ipv4.neigh.default.gc_thresh3 = 2048

# Tell the gc when to become aggressive with arp table cleaning.
# Adjust this based on size of the LAN. 1024 is suitable for most /24 networks
net.ipv4.neigh.default.gc_thresh2 = 1024

# Adjust where the gc will leave arp table alone - set to 32.
net.ipv4.neigh.default.gc_thresh1 = 32

# Adjust to arp table gc to clean-up more often
net.ipv4.neigh.default.gc_interval = 30

# Increase TCP queue length
net.ipv4.neigh.default.proxy_qlen = 96
net.ipv4.neigh.default.unres_qlen = 6

# Enable Explicit Congestion Notification (RFC 3168), disable it if it doesn't work for you
net.ipv4.tcp_ecn = 1
net.ipv4.tcp_reordering = 3

# How many times to retry killing an alive TCP connection
net.ipv4.tcp_retries2 = 15
net.ipv4.tcp_retries1 = 3

# Avoid falling back to slow start after a connection goes idle
# keeps our cwnd large with the keep alive connections (kernel > 3.6)
net.ipv4.tcp_slow_start_after_idle = 0

# Allow the TCP fastopen flag to be used, beware some firewalls do not like TFO! (kernel > 3.7)
net.ipv4.tcp_fastopen = 3

# This will enusre that immediatly subsequent connections use the new values
net.ipv4.route.flush = 1
net.ipv6.route.flush = 1

    # 具体值根据服务器硬件计算,配置不当可能导致过早关闭TCP连接
    # net.netfilter.nf_conntrack_max = 1048576
    # net.netfilter.nf_conntrack_tcp_timeout_established = 1200

3.nginx和lua防御cc攻击

参考了opencdn团队的做法,通过nginx和lua来防御cc,原理见下面的参考文章,效果很棒
nginx需要编译lua模块,见:https://opswill.com/articles/nginx-install-lua-and-lua-based-waf.html
在nginx.conf的http段中加入:

limit_req_zone $cookie_token zone=session_limit:20m rate=1r/s;
limit_req_zone $binary_remote_addr $uri zone=auth_limit:20m rate=1r/m;

在server段中加入:

location  / {
    limit_req zone=session_limit burst=5;
    rewrite_by_lua '
        local random = ngx.var.cookie_random
        if (random == nil) then
            return ngx.redirect("/auth?url=" .. ngx.var.request_uri)
        end
        local token = ngx.md5("opencdn" .. ngx.var.remote_addr .. random)
        if (ngx.var.cookie_token ~= token) then
            return ngx.redirect("/auth?url=".. ngx.var.request_uri)
        end
    ';
            proxy_redirect         off;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
                            proxy_pass http://backend;
    }

location /auth {
        limit_req zone=auth_limit burst=1; 
        if ($arg_url = "") {
            return 403;
        }     
        access_by_lua '
            local random = math.random(9999)
            local token = ngx.md5("opencdn" .. ngx.var.remote_addr .. random)
            if (ngx.var.cookie_token ~= token) then
                ngx.header["Set-Cookie"] = {"token=" .. token, "random=" .. random}
                return ngx.redirect(ngx.var.arg_url)
            end
        ';
    }

这个方法会造成搜索引擎蜘蛛一直处在302中,不利于seo,可以通过智能dns来为蜘蛛指定单独的线路。和被打到宕机比起来,seo几乎可以无视

4.iptables限制tcp连接和频率

通过上述的配置,cc攻击流量就处在302中了,但是保险起见对ip进行连接频率和并发限制,限制单ip连接和频率,在/etc/sysconfig/iptables中加入:

#单个IP在60秒内只允许新建20个连接
-A INPUT -i eth0 -p tcp -m tcp --dport 80 -m state --state NEW -m recent --update --seconds 60 --hitcount 20 --name DEFAULT --rsource -j DROP
-A INPUT -i eth0 -p tcp -m tcp --dport 80 -m state --state NEW -m recent --set --name DEFAULT --rsource

#控制单个IP的最大并发连接数为20
-I INPUT -p tcp --dport 80 -m connlimit  --connlimit-above 20 -j REJECT  

#每个IP最多20个初始连接
-A INPUT -p tcp --syn -m connlimit --connlimit-above 20 -j DROP

这样配置后,单个ip能建立的连接不是只有20个,具体能建立多少连接还要看tcp的超时设置,但单个ip不会建立大量的tcp连接消耗系统资源

5.使用fail2ban屏蔽攻击ip

通过上面设置nginx后,cc攻击请求变为302,直接由性能强劲的nginx处理。但是攻击ip还是在不停的访问服务器,消耗着服务器的资源,一旦达到一定数量级,也会严重影响到系统的性能,所以通过分析nginx的访问日志彻底屏蔽这些ip

安装fail2ban并升级iptables至最新:

yum install -y epel-release 
yum install -y fail2ban iptables python-inotify

先看下我nginx的访问日志格式 :

log_format  main  '$remote_addr $status $request $body_bytes_sent [$time_local]  $http_user_agent $http_referer  $http_x_forwarded_for $upstream_addr $upstream_status $upstream_cache_status $upstream_response_time';

攻击日志的效果:

159.138.198.106 302 GET /auth?url=/ HTTP/1.1 235 [17/Oct/2015:21:06:22 +0800]  Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/600.4.10 (KHTML, like Gecko) Version/8.0.4 Safari/600.4.10 -  - - - - -

cc攻击的ip会经过nginx和lua处理后,访问状态变为302,根据nginx的访问日志格式,过滤这些ip和302状态,加入黑名单即可。
新建fail2ban的规则文件/etc/fail2ban/filter.d/nginx-302-cc.conf,内容为:

[Definition]
failregex = <HOST> 302.(GET|POST)*.*HTTP/1.*$
ignoreregex =

新建fail2ban的配置文件/etc/fail2ban/jail.d/nginx-anti-302.conf,内容为:

[nginx-anti-302]
enabled = true
port = http
filter = nginx-302-cc
logpath = /opt/nginx/logs/nixops.me/access_web.log
findtime = 60     #检测60秒内的日志
bantime = 900     #屏蔽ip的时间为15分钟
maxretry = 90      #达到90次就屏蔽
    backend = pyinotify #使用pyinotify检测日志变化,被攻击时检测海量日志时性能最好
    banaction = iptables-ipset-proto6-allports  #使用ipset屏蔽IP,使用iptables屏蔽大量IP需要时非常慢,并且资源占用非常大

访客访问一次网站会产生2次302,这样配置后60秒内允许45次正常的访问,基本上不会屏蔽正常访客

如果使用iptables屏蔽,需注意fail2ban-0.9.3在执行iptables命令时,会加上了-w参数防止规则冲突,iptables-1.4.20以后才有这个参数,而CentOS 6 的iptables是1.4.7,导致iptables规则添加失败,解决方法是删除iptables-common.conf中的<lockingopt>

sed -i 's/iptables = iptables <lockingopt>/iptables = iptables/' /etc/fail2ban/action.d/iptables-common.conf

启动fail2ban :

service fail2ban start    

通过以上设置实现了:

  1. 增大了系统的吞吐量
  2. cc流量直接由高性能的nginx返回302,不会proxy_pass到后端的服务器或应用
  3. 限制单个ip建立的tcp连接数量和频率
  4. 恶意攻击ip实时黑名单

实际使用效果非常不错。面对专业的ddos玩家,在好的系统终有薄弱的环节,攻击达到一定规模,基本上是不可防的,但是可以尽量利用有限的资源和攻击者周旋,提高攻击的门槛。当然,要是烧的起钱,这篇文章可以无视

参考文章:
http://drops.wooyun.org/tips/734
https://klaver.it/linux/sysctl.conf
http://wsgzao.github.io/post/sysctl/
http://blog.j3l11234.com/2015/09/21/centos_fail2ban/

使用script录制终端操作

script是一个非常炫酷的命令,它可以将终端的所有操作和输入输出录制下来,并通过 scriptreplay播放,是命令行版的"屏幕录像专家"。非常实用,例如你想教很多人配置一个软件,可以在自己配置时,将过程录下来,然后发给别人自学,灰常的优雅!

一.安装

多数操作系统都默认安装了,Redhat/Fedora/CentOS:


yum install util-linux-ng

Debian/ubuntu:

apt-get install bsdutils

二、录制和播放

2.1 录制

script -t -a 2> /tmp/time.txt /tmp/record.txt

为了不影响操作,要使用错误重定向,在录制过程中,使用 Ctrl+d 或者 exit 结束录制

简单说下命令的参数:

-t 是把时间数据输出到标准错误(standard error), 所以要用 2>/tmp/time.txt 把数据重定向到文件中
   一些情况下不需要重放,只要记录操作和输入输出,就可以不指定这个参数
-a 追加内容到文件,不会覆盖之前的记录
-q 安静模式,不会提示用户script在运行
-f 在每次写入后清屏,在配合管道使用时很有用 
-c 这些非交互式的运行命令或脚本  在一些程序或脚本在后台运行时很有用

2.2 播放

scriptreplay /tmp/time.txt /tmp/record.txt

2.3 记录用户操作

记录某个用户,在用户的~/.profile文件中加入:

/usr/bin/script -qa /tmp/user_record

记录所有用户的操作,需将上述内容加在/etc/profile文件中。记录用户操作输出会比较多,回放非常耗时,所以通常不记录时间

2.4 实时广播操作

广播自己的操作给服务器上其它用户看,需要先创建一个管道:

mkfifo /tmp/fifo

将scritp输出到管道:

script -f /tmp/fifo

其它用户执行:

cat /tmp/fifo

就能实时查看到操作和输入输出了

参考文章:
http://www.linuxnix.com/record-terminalshell-session-linux/
http://www.cnblogs.com/Suzzz/p/4107700.html

在shell脚本中嵌入文件

linux版的jdk安装包是一个.bin后缀文件,下载后给执行权限就能解压安装,即简单又方便,Nvidia的闭源驱动(.run)也是一样。一直以为这两个安装包是编译好的二进制文件,可安装过程怎么看都像shell脚本,用sh -x 看了下执行过程,果然就是一个shell脚本,只不过脚本最后嵌入了二进制文件。
JDK安装的大致流程:检查磁盘空间 --> 提取包含的二进制文件(UnZipSFX自解压文件)--> 检查checksum --> 解压 -->结束
Nvidia的脚本稍复杂一点,但大致流程也是一样的,照着写了一个例子,可以用来制作包含二进制文件的shell安装包:

#!/bin/sh
PATH=/usr/bin:/bin
umask 022
md5=0ee8c59a12d99fdfd1e95bfda6938e86
pre_install()
{
echo "准备安装环境(略)..."
mkdir ./install.tmp.$$
}
check_sum()
{
if [ -x /usr/bin/md5sum ]&&[ -f "install.tmp.$$/extract.$$" ]; then
echo "正在检查md5......"
sum_tmp=($(/usr/bin/md5sum install.tmp.$$/extract.$$))
if [ $sum_tmp != $md5 ]; then
    echo "文件md5不一致,请检查文件完整性,退出!"
    exit 1
fi
else
        echo "找不到md5sum命令或文件未提取,退出"
    exit 1
fi
}
extract()
{
echo "从脚本中提取文件"
line_number=`awk '/^__BIN_FILE_BEGIN__/ {print NR + 1; exit 0; }' "$0"`    
tail -n +$line_number "$0" >./install.tmp.$$/extract.$$
#tail -n +$line_number "$0" >./install.tmp.$$/extract_tmp.$$
#base64 -d ./install.tmp.$$/extract_tmp.$$ >./install.tmp.$$/extract.$$
}
install()
{
    echo "安装中(略)..."
}
post_install()
{
    echo "配置中(略)..." 
    echo "清理临时文件"
    rm -rf install.tmp.$$
}

main()
{
    pre_install
    extract
    check_sum
    install
    post_install
    exit 0
}

main
#这行下面接二进制文件
__BIN_FILE_BEGIN__

二进制文件可以是zip/tar/可执行文件等等,将文件追加到脚本里,例如追加zip文件到脚本里:

cat binary.zip >>shell.sh

这种方法提取后会改变binary.zip的md5值,校检的时候要用提取后文件的md5(./install.tmp.$$/extract.$$)
还有一种方法可以不改变binary.zip的md5,就是使用base64将文件加密成文本:

base64 binary.zip >>shell.sh

在脚本extract()中,使用注释里的命令,网上有很多教程是用uuencode加密的,这个也行,不过很多系统默认是没有安装uuencode,通用性会下降,还是用base64好

yum报错解决手记

帮别人配置环境,系统是centos 6.5 64位,用yum安装软件时一直报错,前后一共遇到两个错误:

错误1:

[root@localhost yum.repos.d]# yum install telnet 
Loaded plugins: fastestmirror, security
Loading mirror speeds from cached hostfile
http://mirror.centos.org/centos/%24releasever/os/x86_64/repodata/repomd.xml: [Errno 14] HTTP Error 404: Not Found
Trying other mirror.
Error: Cannot retrieve repository metadata (repomd.xml) for repository: base. Please verify its path and try again

错误2:

[root@localhost etc]# yum install telnet 
Loaded plugins: fastestmirror, security
Determining fastest mirrors
YumRepo Error: All mirror URLs are not using ftp, http[s] or file.
 Eg. $releasever is not a valid and current release or hasnt been released yet/
removing mirrorlist with no valid mirrors: /var/cache/yum/base/mirrorlist.txt
Error: Cannot find a valid baseurl for repo: base

服务器的网络和dns是没问题的,yum.repo.d/Centos-Base.repo配置是默认的,其它配置文件不清楚有没有改过。

这两个错误都是和yum的$releasever变量有关,这个变量会读取centos-release包的内容,解决方法是编辑/etc/yum.conf文件,将distroverpkg改为redhat-release或者centos-release即可

vim /etc/yum.conf
distroverpkg=redhat-release 

当然,要保证服务器有centos-release包,这个包是随系统安装的,而且一般人不会干掉它

参考文章:

http://www.opstool.com/article/294

lfs-7.7学习笔记(4)系统配置

lfs-7.7学习笔记(4)系统配置

五、基本系统配置

到这一步,基本系统就已经编译好了,只需要配置即可,原来的tools已经目录没用了,sources目录还后面编译内核时还要用到,暂时要保留,不想保留拷贝一份linux-3.19.tar.xz出来也可以。

重新进入chroot环境,先logout,在进入:


chroot "$LFS" /usr/bin/env -i \
 HOME=/root TERM="$TERM" PS1='\u:\w\$ ' \
 PATH=/bin:/usr/bin:/sbin:/usr/sbin \
 /bin/bash --login

干掉ools目录:

rm -rf  /tools

如果宿主系统有重启过,或卸载过虚拟内核文件系统,进入chroot前需要重新挂载:


mount -v --bind /dev $LFS/dev
mount -vt devpts devpts $LFS/dev/pts -o gid=5,mode=620
mount -vt proc proc $LFS/proc
mount -vt sysfs sysfs $LFS/sys
mount -vt tmpfs tmpfs $LFS/run

5.1 通用网络配置

5.1.1 配置网卡

默认情况下网卡的名字不是eth0,需要使用udev绑定,绑定方法:
查看网卡的mac地址:

ip link

假设物理网卡的地址是A0:48:1C:9A:01:5C,新建udev配置文件:

touch /etc/udev/rules.d/70-persistent-net.rules

内容为:

SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="A0:48:1C:9A:01:5C", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth0"

这样在启动时udev就会将物理网卡绑定到eth0,可以使用eth0配置网络

配置DHCP还是静态IP,按个人情况,二选一,配置静态ip:

cat > /etc/systemd/network/10-static-eth0.network << "EOF"
[Match]
Name=eth0
[Network]
Address=192.168.0.2/24
Gateway=192.168.0.1
DNS=192.168.0.1
EOF

配置DHCP:


cat > /etc/systemd/network/10-dhcp-eth0.network << "EOF"
[Match]
Name=eth0
[Network]
DHCP=yes
EOF

5.1.2 创建 /etc/resolv.conf

resolv.conf是静态dns的配置文件

cat > /etc/resolv.conf << "EOF"
# Begin /etc/resolv.conf
domain <Your Domain Name>
nameserver <IP address of your primary nameserver>
nameserver <IP address of your secondary nameserver>

# End /etc/resolv.conf
EOF

创建标准的符号链接:

ln -sfv /run/systemd/resolve/resolv.conf /etc/resolv.conf

5.1.3 创建主机名

echo "LFS" > /etc/hostname

5.1.4 创建hosts文件

在4.5.35 安装 Perl中已经创建了 hosts文件,这里省略,需要注意的是主机名应该在hosts中
如:

cat /etc/hosts
127.0.0.1 localhost LFS

5.2 配置系统时间

system的会读取/etc/adjtime的时间配置,所以创建/etc/adjtime:

cat > /etc/adjtime << "EOF"
0.0 0 0.0
0
LOCAL
EOF

5.3 设置系统区域

查看 Glibc 支持的本地字符集:

locale -a

按照之前编译glibc时的配置,系统中是有zh_CN.gb18030,没有zh_CN.utf8,安装:

localedef -i zh_CN -f UTF-8 zh_CN.utf8

创建 /etc/locale.conf:

cat > /etc/locale.conf << "EOF"
LANG=zh_CN.UTF8
EOF

5.4 配置键盘布局

创建 /etc/inputrc 文件:

cat > /etc/inputrc << "EOF"
# Begin /etc/inputrc
# Modified by Chris Lynn <roryo@roryo.dynup.net>
# Allow the command prompt to wrap to the next line
set horizontal-scroll-mode Off
# Enable 8bit input
set meta-flag On
set input-meta On
# Turns off 8th bit stripping
set convert-meta Off
# Keep the 8th bit for display
set output-meta On
# none, visible or audible
set bell-style none
# All of the following map the escape sequence of the value
# contained in the 1st argument to the readline specific functions
"\eOd": backward-word
"\eOc": forward-word
# for linux console
"\e[1~": beginning-of-line
"\e[4~": end-of-line
"\e[5~": beginning-of-history
"\e[6~": end-of-history
"\e[3~": delete-char
"\e[2~": quoted-insert
# for xterm
"\eOH": beginning-of-line
"\eOF": end-of-line
# for Konsole
"\e[H": beginning-of-line
"\e[F": end-of-line
# End /etc/inputrc
EOF

5.5 配置shell

创建/etc/shells 文件:

cat > /etc/shells << "EOF"
# Begin /etc/shells
/bin/sh
/bin/bash    
# End /etc/shells
EOF

5.6 配置systemd

禁止 /tmp 使用 tmpfs:

ln -sfv /dev/null /etc/systemd/system/tmp.mount

六、 LFS 系统引导配置

6.1 创建 /etc/fstab 文件


cat > /etc/fstab << "EOF"
# Begin /etc/fstab
# 文件系统 挂载点 文件类型 挂载选项 dump fsck
# order
/dev/sdb1 /  defaults 1 1
# End /etc/fstab
EOF

6.2 编译内核

令准备编译:


make mrproper

生成内核配置文件:


make defconfig

会根据机器架构生成一份配置,保存在内核源码目录下.config文件中,确保以下内容是打开的:

CONFIG_FHANDLE=y
CONFIG_CGROUPS=y
CONFIG_SECCOMP=y
CONFIG_IPV6=y
CONFIG_DEVTMPFS=y
CONFIG_DMIID=y
ONFIG_INOTIFY_USER=y
CONFIG_AUTOFS4_FS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_TMPFS_XATTR=y

如果宿主机是vmware,还需要如下配置:

CONFIG_FUSION=y
CONFIG_FUSION_SPI=y
CONFIG_FUSION_SAS=y
CONFIG_FUSION_MAX_SGE=y
CONFIG_FUSION_CTL=y
CONFIG_FUSION_LOGGING=y

CONFIG_VMWARE_BALLOON=y
CONFIG_VMWARE_PVSCSI=y

CONFIG_HYPERVISOR_GUEST=Y

不添加这些配置,LFS启动时会报类似"kernel panic"或者"VFS: unable to mount root fs"的错误

或者通过下面命令,使用命令行下的图形界面设置:

make LANG=zh_CN.UTF8 LC_ALL= menuconfig

编译:


make

安装模块:

make modules_install

根据必要的文件到/boot下:

cp -v arch/x86_64/boot/bzImage /boot/vmlinuz-3.19-lfs-7.7-systemd
cp -v System.map /boot/System.map-3.19

安装 Linux 内核文档:

install -d /usr/share/doc/linux-3.19
cp -r Documentation/* /usr/share/doc/linux-3.19

6.3 设置启动过程

安装Grub:


grub-install /dev/sdb

创建 GRUB 配置文件:

cat > /boot/grub/grub.cfg << "EOF"
# Begin /boot/grub/grub.cfg
set default=0
set timeout=5
insmod ext2
set root=(hd0,1)   
menuentry "GNU/Linux, Linux 3.19-lfs-7.7-systemd" {
 linux /boot/vmlinuz-3.19-lfs-7.7-systemd root=/dev/sda1 ro
}
EOF

grub配置文件中root=/dev/sda1 ro是磁盘挂载为只读,测试启动成功后可以改成rw

6.4 创建/etc/os-release文件

cat > /etc/os-release << "EOF"
NAME="Linux From Scratch"
VERSION="7.7-systemd"
ID=lfs
PRETTY_NAME="Linux From Scratch 7.7-systemd"
EOF

到这里新系统就大功告成了,虽然好还有好多软件要配置,但可以开机启动,体验自己编译好的新系统了
最后可以去官方注册为LFS用户: http://www.linuxfromscratch.org/cgi-bin/lfscounter.php

lfs-7.7学习笔记(1)准备篇
lfs-7.7学习笔记(2)构建临时系统
lfs-7.7学习笔记(3)构建 LFS 系统
lfs-7.7学习笔记(4)系统配置

最新文章

最近回复

分类

归档

统计

  • 文章总数:168篇
  • 分类总数:5个
  • 评论总数:103条
  • 页面总数:172个
  • 本站运行:4885天

其它