6.1 网络文件共享:FTP

FTP工作原理

     FTP使用2个TCP端口,首先是建立一个命令端口(控制端口),然后再产生一个数据端口。ftp工作在主动模式使用tcp 21 和 20 两个端口,而工作在被动模式会工作在大于1024随机端口。

主动模式(port)

    主动方式的FTP是这样的:客户端从一个任意的非特权端口N(N>1024)连接到FTP服务器的命令端口,即tcp 21端口。紧接着客户端开始监听端口N+1,并发送FTP命令“port N+1”到FTP服务器。最后服务器会从它自己的数据端口(20)连接到客户端指定的数据端口(N+1),这样客户端就可以和ftp服务器建立数据传输通道了。

针对FTP服务器的防火墙来说,必须允许以下通讯才能支持主动方式FTP:
1、客户端口>1024端口到FTP服务器的21端口 (入:客户端初始化的连接 S<-C)
2、FTP服务器的21端口到客户端>1024的端口(出:服务器响应客户端的控制端口 S->C)
3、FTP服务器的20端口到客户端>1024的端口(出:服务器端初始化数据连接到客户端的数据端口 S->C)

4、客户端>1024端口到FTP服务器的20端口(入:客户端发送ACK响应到服务器的数据端口 S<-C)

被动模式(pasv)

    在被动方式FTP中,命令连接和数据连接都由客户端。当开启一个FTP连接时,客户端打开两个任意的非特权本地端口(N >1024和N+1)。第一个端口连接服务器的21端口,但与主动方式的FTP不同,客户端不会提交PORT命令并允许服务器来回连它的数据端口,而是提交 PASV命令。这样做的结果是服务器会开启一个任意的非特权端口(P >1024),并发送PORT P命令给客户端。然后客户端发起从本地端口N+1到服务器的端口P的连接用来传送数据。

对于服务器端的防火墙来说,必须允许下面的通讯才能支持被动方式的FTP:
1、客户端>1024端口到服务器的21端口(入:客户端初始化的连接 S<-C)
2、服务器的21端口到客户端>1024的端口(出:服务器响应到客户端的控制端口的连接 S->C)
3、客户端>1024端口到服务器的大于1024端口(入:客户端初始化数据连接到服务器指定的任意端口 S<-C)

4、服务器的大于1024端口到远程的大于1024的端口(出:服务器发送ACK响应和数据到客户端的数据端口 S->C)

    状态码

1XX:信息 125:数据连接打开
2XX:成功类状态 200:命令OK 230:登录成功
3XX:补充类 331:用户名OK
4XX:客户端错误 425:不能打开数据连接
5XX:服务器错误 530:不能登录

    用户认证

匿名用户:ftp,anonymous,对应Linux用户ftp
系统用户:Linux用户,用户/etc/passwd,密码/etc/shadow

虚拟用户:特定服务的专用用户,独立的用户/密码文件

FTP服务搭建

    使用 vsftpd 提供 ftp 服务。

[root@CentOS74 ~]# yum install vsftpd

匿名用户(映射为系统用户ftp )共享文件位置:/var/ftp
系统用户共享文件位置:用户家目录
虚拟用户共享文件位置:为其映射的系统用户的家目录

    修改 vsftpd 配置,配置文件存放在 /etc/vsftpd/vsftpd.conf

    服务配置

命令端口:listen_port=21

主动模式端口:ftp_data_port=20

被动模式端口范围:pasv_min_port=6000        pasv_max_port=6010(0为随机分配)
linux客户端默认使用被动模式,windows 客户端默认使用主动模式。

使用当地时间:use_localtime=YES(默认为NO,使用GMT)

启用记录上传下载日志:xferlog_enable=YES

记录wu-ftp格式日志:xferlog_std_format=YES

日志文件存放路径:xferlog_file=/var/log/xferlog

记录vsftpd格式日志:dual_log_enable=YES

日志文件存放路径:vsftpd_log_file=/var/log/vsftpd.log

登录提示信息:ftpd_banner=“welcome to mage ftp server"(高优先级)

登录提示信息文件:banner_file=/etc/vsftpd/ftpbanner.txt

目录访问提示信息:dirmessage_enable=YES

目录访问提示信息存放文件:message_file=.message(在对应文件夹里)

    匿名用户配置

支持匿名用户:anonymous_enable=YES

匿名用户略过口令检查:no_anon_password=YES

只能下载权限比444大的文件:anon_world_readable_only=YES

匿名上传文件:anon_upload_enable=YES

匿名上传目录:anon_mkdir_write_enable=YES

可删除和修改上传的文件:anon_other_write_enable=YES

ftp> put anaconda-ks.cfg        #当开启匿名上传后,发现还是无法上传文件
local: anaconda-ks.cfg remote: anaconda-ks.cfg
227 Entering Passive Mode (192,168,30,74,176,212).
550 Permission denied.          #权限被拒绝,原因是目标文件夹对ftp用户没有写权限
[root@CentOS74 ftp]# setfacl -m u:ftp:rwx /var/ftp/pub/   #对ftp用户通过acl授权
[root@CentOS74 ftp]# getfacl /var/ftp/pub/
getfacl: Removing leading '/' from absolute path names
# file: var/ftp/pub/
# owner: root
# group: root
user::rwx
user:ftp:rwx    #ftp用户对目录/var/ftp/pub/拥有读写执行权限
group::r-x
mask::rwx
other::r-x
ftp> put anaconda-ks.cfg        #上传文件
local: anaconda-ks.cfg remote: anaconda-ks.cfg
227 Entering Passive Mode (192,168,30,74,194,80).
150 Ok to send data.
226 Transfer complete.
1433 bytes sent in 0.000365 secs (3926.03 Kbytes/sec)
ftp> ls
227 Entering Passive Mode (192,168,30,74,88,235).
150 Here comes the directory listing.
-rw-------    1 14       50           1433 Jun 26 12:19 anaconda-ks.cfg
226 Directory send OK.

指定匿名上传文件的umask:anon_umask=077

上传文件时更改所有者:chown_uploads=YES

指定上传文件默认的所有者:chown_username=jiangbowen

指定上传文件默认的权限:chown_upload_mode=0644

[root@CentOS74 pub]# ll
total 4
-rw------- 1 ftp ftp 1433 Jun 26 20:19 anaconda-ks.cfg
ftp> put test 
local: test remote: test
227 Entering Passive Mode (192,168,30,74,113,195).
150 Ok to send data.
226 Transfer complete.
[root@CentOS74 pub]# ll
total 0
-rw-r--r-- 1 jiangbowen ftp 0 Jun 26 20:36 test   #所有者和权限修改为配置文件中的定义

    系统用户配置

所有系统用户都映射成guest用户:guest_enable=YES

指定guest用户:guest_username=ftpuser

[root@CentOS74 pub]# useradd -d /data/ftp ftpuser
[root@CentOS74 pub]# chmod 555 /data/ftp/    #根目录不能有写权限,同时又要访问根目录,所以要将权限设置为555
[root@CentOS74 pub]# ll /data/ftp/ -d
dr-xr-xr-x 2 ftpuser ftpuser 74 Jun 26 21:00 /data/ftp/
ftp> ls
227 Entering Passive Mode (192,168,30,74,23,54).
150 Here comes the directory listing.
-rw-r--r--    1 0        0               0 Jun 26 13:00 dir1
226 Directory send OK.
ftp> pwd
257 "/"    #将/data/ftp目录映射为根目录

允许linux用户登录:local_enable=YES

允许linux用户上传文件:write_enable-YES

指定系统用户上传文件的默认权限:local_umask=022

非匿名用户登录所在目录:local_root=/ftproot

[root@CentOS74 ftp]# mkdir /data/ftproot
[root@CentOS74 ftp]# chmod 555 /data/ftproot/
[root@CentOS74 ftp]# touch /data/ftproot/roottest
ftp> pwd
257 "/"
ftp> ls
227 Entering Passive Mode (192,168,30,74,64,235).
150 Here comes the directory listing.
-rw-r--r--    1 0        0               0 Jun 26 13:09 roottest   #根目录为/data/ftproot/
226 Directory send OK.

禁锢系统用户:chroot_local_user=YES

Name (192.168.30.74:root): jiangbowen
331 Please specify the password.
Password:
500 OOPS: vsftpd: refusing to run with writable root inside chroot()
Login failed.                                                    #开启禁锢功能后,系统用户的家目录就是各自的根
421 Service not available, remote server has closed connection   #jiangbowen用户的家目录有写权限,没有家目录也会登陆失败

禁锢(或不禁锢)列表中的系统用户:chroot_list_enable=YES(NO)

指定禁锢用户列表:chroot_list_file=/etc/vsftpd/chroot_list

    登陆与连接配置

使用pam模块完成用户认证:pam_service_name=vsftpd

    查看 vsftpd 模块的配置文件 /etc/pam.d/vsftpd

[root@CentOS74 ftp]# cat /etc/pam.d/vsftpd
#%PAM-1.0
session    optional     pam_keyinit.so    force revoke
auth       required	pam_listfile.so item=user sense=deny file=/etc/vsftpd/ftpusers onerr=succeed
auth       required	pam_shells.so                  ^拒绝指定文件中存放的用户登陆
auth       include	password-auth
account    include	password-auth
session    required     pam_loginuid.so
session    include	password-auth

    查看 /etc/vsftpd/ftpusers 文件中的用户

[root@CentOS74 ftp]# cat /etc/vsftpd/ftpusers
# Users that are not allowed to login via ftp
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
news
uucp
operator
games
nobody

启用控制用户登录的列表文件:userlist_enable=YES

userlist 为黑名单:userlist_deny=YES(NO为白名单)

用户列表的存放的路径:userlist_file=/etc/vsftpd/users_list

[root@CentOS74 pam.d]# cat /etc/vsftpd/user_list 
# vsftpd userlist
# If userlist_deny=NO, only allow users in this file
# If userlist_deny=YES (default), never allow users in this file, and
# do not even prompt for a password.
# Note that the default vsftpd pam config also checks /etc/vsftpd/ftpusers
# for users that are denied.
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
news
uucp
operator
games
nobody

    使用 root 用户登陆 ftp

Name (192.168.30.74:root): root
530 Permission denied.
Login failed.    #登陆失败

最大并发连接数:max_clients=0

每个IP同时发起的最大连接数:max_per_ip=0(0为不限制)

vsftpd服务指定用户身份运行:nopriv_user=nobody

[root@CentOS74 pam.d]# ps aux | grep ftp
root      11920  0.0  0.0  53212   576 ?        Ss   22:27   0:00 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
root      11931  0.0  0.0  55336  1336 ?        Ss   22:30   0:00 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
jiangbo+  11932  0.0  0.0  55348   848 ?        S    22:30   0:00 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf   #以指定用户身份运行

匿名用户的最大传输速率:anon_max_rate=0(0为不限制)

系统用户的最大传输速率:local_max_rate=0

主动模式数据连接超时时长:connect_timeout=60

被动模式数据连接超时时长:accept_timeout=60

数据连接无数据输超时时长:data_connection_timeout=300

无命令操作超时时长:idle_session_timeout=60

以文本方式上传数据:ascii_upload_enable=YES(默认二进制)

以文本方式下载数据:ascii_download_enable=YES

UNIX系列系统默认使用二进制传输数据,DOS系列系统默认使用文本传输数据。

基于SSL的FTPS

(1)创建自签名证书

    使用 make 脚本自动创建

[root@CentOS74 ~]# cd /etc/pki/tls/certs/
[root@CentOS74 certs]# make vsftpd.pem
umask 77 ; \
PEM1=`/bin/mktemp /tmp/openssl.XXXXXX` ; \
PEM2=`/bin/mktemp /tmp/openssl.XXXXXX` ; \
/usr/bin/openssl req -utf8 -newkey rsa:2048 -keyout $PEM1 -nodes -x509 -days 365 -out $PEM2  ; \
cat $PEM1 >  vsftpd.pem ; \
echo ""    >> vsftpd.pem ; \
cat $PEM2 >> vsftpd.pem ; \
rm -f $PEM1 $PEM2
Generating a 2048 bit RSA private key
..........................................................................................+++
...................+++
writing new private key to '/tmp/openssl.21EOKs'
-----
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) [XX]:CN
State or Province Name (full name) []:henan
Locality Name (eg, city) [Default City]:zhengzhou
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:jiangbowen
Email Address []:

    或者使用 openssl 命令手动创建自签名证书,创建完证书后将证书内容追加至自签证书内

[root@CentOS74 CA]# (umask 066; openssl genrsa -out /etc/pki/CA/private/cakey.pem 2048)
Generating RSA private key, 2048 bit long modulus
.......................+++
......................................+++
e is 65537 (0x10001)
[root@CentOS74 CA]# openssl req -new -x509 -key /etc/pki/CA/private/ftpkey.pem -days 7300 -out /etc/pki/CA/cacert.pem
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) [XX]:CN
State or Province Name (full name) []:HeNan
Locality Name (eg, city) [Default City]:ZhengZhou
Organization Name (eg, company) [Default Company Ltd]:Linux
Organizational Unit Name (eg, section) []:CentOS
Common Name (eg, your name or your server's hostname) []:jiangbowen
Email Address []:

(2)配置 vsftpd 服务支持 SSL

[root@CentOS74 vsftpd]# cat /etc/vsftpd/vsftpd.conf | grep ssl
ssl_enable=YES               #启用SSL
allow_anon_ssl=NO            #匿名不支持SSL
force_local_logins_ssl=YES   #本地用户登录加密
force_local_data_ssl=YES     #本地用户数据传输加密
rsa_cert_file=/etc/pki/tls/certs/vsftpd.pem  #证书文件存放路径

(3)使用 filezilla 登陆 ftp 服务器,linux系统中 ftp 工具不支持加密传输

vsftpd虚拟用户

    所有虚拟用户会统一映射为一个指定的系统帐号:访问共享位置,即为此系统帐号的家目录。各虚拟用户可被赋予不同的访问权限,通过匿名用户的权限控制参数进行指定。

基于文件验证

(1)创建用户数据库文件

[root@CentOS74 vsftpd]# cat /etc/vsftpd/vusers.txt   #创建用户文本,用户密码成对出现
jiangbowen
123456
ftpuser
123456
nohome
123456
[root@CentOS74 vsftpd]# db_load -T -t hash -f vusers.txt vusers.db   #使用db_load生成用户数据库文件
[root@CentOS74 vsftpd]# chmod 600 vusers.db    #更改数据库文件权限
[root@CentOS74 vsftpd]# ll vusers.db
-rw------- 1 root root 12288 Jun 28 05:27 vusers.db

(2)创建用户和访问 FTP 目录

[root@CentOS74 vsftpd]# useradd -d /var/ftproot -s /sbin/nologin vuser   #创建本地映射用户
[root@CentOS74 vsftpd]# chmod 555 /var/ftproot/                          #修改映射用户及目录权限,去掉写权限
[root@CentOS74 vsftpd]# ll -d /var/ftproot/
dr-xr-xr-x 2 vuser vuser 62 Jun 28 05:31 /var/ftproot/
[root@CentOS74 vsftpd]# mkdir /var/ftproot/testdir                       #创建文件夹,用于上传文件
[root@CentOS74 vsftpd]# setfacl -m u:vuser:rwx /var/ftproot/testdir      #赋予映射用户读写执行的ACL权限
[root@CentOS74 vsftpd]# ll /var/ftproot/
total 0
drwxrwxr-x+ 2 root root 6 Jun 28 05:32 testdir

(3)创建 pam 配置文件,并启用 pam 模块

[root@CentOS74 ~]# cat /etc/pam.d/vsftpd.db            #创建pam模块配置文件
auth required pam_userdb.so db=/etc/vsftpd/vusers      #根据用户数据库,使用pam_userdb模块
account required pam_userdb.so db=/etc/vsftpd/vusers   #控制登陆
[root@CentOS74 ~]# cat /etc/vsftpd/vsftpd.conf | grep pam
pam_service_name=vsftpd.db                             #启用vsftpd.db
[root@CentOS74 ~]# cat /etc/vsftpd/vsftpd.conf | grep guest
guest_enable=YES      #启用虚拟用户
guest_username=vuser  #指定虚拟用户

(4)创建远程用户的独立配置文件

[root@CentOS74 ~]# cat /etc/vsftpd/vsftpd.conf | grep user_config
user_config_dir=/etc/vsftpd/vusers.d/
[root@CentOS74 ~]# mkdir /etc/vsftpd/vusers.d/

    创建用户的配置文件,使其可读可写

[root@CentOS74 ~]# cat /etc/vsftpd/vusers.d/jiangbowen
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES

    创建用户的配置文件,修改其登陆目录

[root@CentOS74 ~]# cat /etc/vsftpd/vusers.d/nohome
local_root=/var/nohome       #更改用户的登陆目录
[root@CentOS74 ~]# mkdir /var/nohome   #创建对应的目录
[root@CentOS74 ~]# setfacl -m u:vuser:rwx /var/nohome/   #赋予虚拟用户权限

    不创建用户配置文件的话,其权限根据主配置文件中对虚拟用户的定义

测试三个用户登陆 ftp 服务器的情况

Name (192.168.30.74:root): jiangbowen    #拥有读写权限
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd testdir
250 Directory successfully changed.
ftp> ls
227 Entering Passive Mode (192,168,30,74,252,126).
150 Here comes the directory listing.
-rw-r--r--    1 0        0               0 Jun 27 22:16 ftproot.mark
226 Directory send OK.
ftp> put anaconda-ks.cfg        
local: anaconda-ks.cfg remote: anaconda-ks.cfg
227 Entering Passive Mode (192,168,30,74,218,239).
150 Ok to send data.            #可以上传文件,并新建目录
226 Transfer complete.
1433 bytes sent in 0.0102 secs (140.56 Kbytes/sec)
ftp> ls
227 Entering Passive Mode (192,168,30,74,211,178).
150 Here comes the directory listing.
-rw-------    1 1003     1003         1433 Jun 27 22:19 anaconda-ks.cfg
-rw-r--r--    1 0        0               0 Jun 27 22:16 ftproot.mark
226 Directory send OK.
Name (192.168.30.74:root): ftpuser     #没有单股设置权限,使用默认配置
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd testdir
250 Directory successfully changed.
ftp> ls
227 Entering Passive Mode (192,168,30,74,206,144).
150 Here comes the directory listing.
-rw-------    1 1003     1003         1433 Jun 27 22:19 anaconda-ks.cfg
-rw-r--r--    1 0        0               0 Jun 27 22:16 ftproot.mark
226 Directory send OK.
ftp> put test
local: test remote: test
227 Entering Passive Mode (192,168,30,74,215,168).
550 Permission denied.            #无法上传文件,权限被拒绝
Name (192.168.30.74:root): nohome    #更改登陆目录
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> pwd
257 "/"                 #登陆目录映射为根
ftp> ls
227 Entering Passive Mode (192,168,30,74,96,172).
150 Here comes the directory listing.
-rw-r--r--    1 0        0               0 Jun 27 22:17 nohome.mark   #成功更改登陆目录
226 Directory send OK.

基于MySql验证

(1)安装必要组件 mariadb 服务器、开发包,pam 模块开发包

[root@CentOS74 ~]# yum install mariadb-devel pam-devel mariadb-server.x86_64

(2)编译安装 pam_mysql 模块,源码包需要从网络上下载

[root@CentOS74 /]# ls /lib64/security/pam_mysql.so
/lib64/security/pam_mysql.so

(3)配置 MySql 数据库

    创建管理用户

MariaDB [(none)]> GRANT SELECT ON ftpuser.* TO ftpadmin@192.168.30.74 IDENTIFIED BY 'dengniaiwo123';
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

    新建虚拟用户数据库和用户列表

MariaDB [(none)]> USE ftpuser;
Database changed
MariaDB [ftpuser]> CREATE TABLE ftpuserlist (id int auto_increment primary key,name char(30),passwd char(50));
Query OK, 0 rows affected (0.02 sec)
MariaDB [ftpuser]> INSERT INTO ftpuserlist(name,passwd) values('ftpuser1',password('123456')),('ftpuser2',password('123456')),('ftpuser3',password('123456'));
Query OK, 3 rows affected (0.03 sec)
Records: 3  Duplicates: 0  Warnings: 0
[root@CentOS74 /]# mysql -uftpadmin -h192.168.30.74 -pdengniaiwo123   #测试数据库连接
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 12
Server version: 5.5.56-MariaDB MariaDB Server

Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> select * from ftpuser.ftpuserlist;    #查看能否查找ftpuserlist表
+----+----------+-------------------------------------------+
| id | name     | passwd                                    |
+----+----------+-------------------------------------------+
|  1 | ftpuser1 | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
|  2 | ftpuser2 | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
|  3 | ftpuser3 | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
+----+----------+-------------------------------------------+
3 rows in set (0.00 sec)

(4)配置 vsftpd 服务

    根据数据库信息创建 pam_mysql 模块的配置文件

[root@CentOS74 vsftpd]# cat /etc/pam.d/vsftpd.mysql
auth required pam_mysql.so user=ftpadmin passwd=dengniaiwo123 host=192.168.30.74 db=ftpuser table=ftpuserlist usercolumn=name passwdcolumn=passwd crypt=2
account required pam_mysql.so user=ftpadmin passwd=dengniaiwo123 host=192.168.30.74 db=ftpuser table=ftpuserlist usercolumn=name passwdcolumn=passwd crypt=2 

    crypt:加密方式

0表示不加密
1表示crypt(3)加密
2表示使用mysql password()函数加密
3表示md5加密

4表示sha1加密

    修改主配置文件,与基于文件验证一样,只不过将 pam 模块加载为 pam_mysql 模块

[root@CentOS74 vsftpd]# cat /etc/pam.d/vsftpd.mysql
auth required pam_mysql.so user=ftpadmin passwd=dengniaiwo host=192.168.30.74 db=ftpuser table=ftpuserlist usercolumn=name passwdcolumn=passwd crypt=2
account required pam_mysql.so user=ftpadmin passwd=dengniaiwo host=192.168.30.74 db=ftpuser table=ftpuserlist usercolumn=name passwdcolumn=passwd crypt=2 
[root@CentOS74 vsftpd]# cat vsftpd.conf | grep vsftpd.mysql
pam_service_name=vsftpd.mysql

测试登陆使用虚拟用户 ftp 服务器

Name (192.168.30.74:root): ftpuser1
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd testdir
250 Directory successfully changed.
ftp> ls
227 Entering Passive Mode (192,168,30,74,70,62).
150 Here comes the directory listing.
-rw-------    1 1003     1003         1433 Jun 27 22:19 anaconda-ks.cfg
-rw-r--r--    1 0        0               0 Jun 27 22:16 ftproot.mark
226 Directory send OK.





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值