首页 > 系统服务 > 详细

笔记:Linux上实验 GRE Bridge ,IPsec , NFQUEUE

时间:2020-04-04 23:41:13      阅读:112      评论:0      收藏:0      [点我收藏+]

1. 实验背景

如下是网络拓扑图:

技术分享图片

我们使用GRETAP  Tunnel 互联 A&B;

GRE 是encapsulate为 IP packets;

GRETAP encapsulate为 Ethernet frames,请留意 Linux GRETAP可与Cisco EoGRE建立互联。

 

2. 使用iproute2创建GRETAP

# 请先确认已安装iproute,若未安装,可先安装iproute:

yum install -y iproute

# 创建、启用、查看gretap interface

routerA# ip link add gretap1 type gretap local 192.168.200.1 remote 172.16.0.1 dev eth1
routerA# ip link set gretap1 up
routerA# ip link show gretap1
6: gretap@eth1: <BROADCAST,MULTICAST> mtu 1462 qdisc noop state DOWN mode DEFAULT qlen 1000 link/ether 62:24:67:45:44:ad brd ff:ff:ff:ff:ff:ff

目的是:创建gretap interface到tunnel 两侧的bridge,可以让siteA与siteB 是桥接在一起。然后使用IPsec去加密siteA&B之间的GRE traffic 。

 

3. MTU问题

如上述创建的GRETAP,MTU为1462。计算方式:

1500 (物理接口MTU) - 20 (GRE新增的外部IP包头) - 4 (GRE header) - 14 (封装的ethernet header) = 1462.

对于IP packet的传输,当传输packet大于MTU时,经过的路由设备允许切片重传就保障数据继续传输(当然重传会会成倍增加网络传输延迟)。对于Ethernet Network 且 gretap 属于桥接接口,MTU必须一致才能通信,否则会被丢弃。下面,我们来验证一下:

# 在routerA 添加gretap interface到bridge  br0:

routerA# ip link add br0 type bridge
routerA# ip link set eth0 down
routerA# ip addr del 10.32.x.x/24 dev eth0    # 移除eth0的IP。此处留意如果是AWS EC2,务必小心;如果是阿里或腾讯Cloud Server,错误也可用控制台管理。建议在本地环境试验。
routerA# ip link set eth0 master br0
routerA# ip link set eth0 up
routerA# ip link set br0 up
routerA# ip addr add 10.0.0.254/24 dev br0
routerA# ip link set gretap1 up
routerA# ip link set gretap1 master br0

# 在routerB 添加gretap interface到bridge  br0:routerB

routerB# ip link add br0 type bridge
routerB# ip link set eth0 down
routerB# ip addr del 10.32.x.x/24 dev eth0   # 移除eth0的IP。此处留意如果是AWS EC2,务必小心;如果是阿里或腾讯Cloud Server,错误也可用控制台管理。建议在本地环境试验。
routerB# ip link set eth0 master br0
routerB# ip link set eth0 up
routerB# ip link set br0 up
routerB# ip addr add 10.0.0.253/24 dev br0
routerB# ip link set gretap1 up
routerB# ip link set gretap1 master br0

# 结果:

hostA# ping -s 172 10.32.0.111
PING 10.32.0.111 (10.32.0.111) 1472(1500) bytes of data.
^C
--- 10.32.0.111 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2015ms

  我们-s发起max size frame,从hostA 无法ping hostB

  通过抓包分析,我们能看到 小型的ARP request/reply frames 是能正常通过tunnel。然而,ICMP request packets是在routerA的br0就被静默丢弃,因为routerA 的br0 MTU依然是1462。

# 如果我们将br0强制调整为1500,让HostA能够通过1500的包到HostB:

  routerA&B的gretap1都需要执行,此处仅展示routerA侧br0:

routerA# ip link show br0
4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1462 qdisc noqueue state UP mode DEFAULT 
    link/ether 00:16:3e:c3:8c:ef brd ff:ff:ff:ff:ff:ff
routerA# ip link set gretap1 mtu 1500
routerA# ip link show br0
4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT 
    link/ether 00:16:3e:c3:8c:ef brd ff:ff:ff:ff:ff:ff

  如果强制将gretap1的MTU从1462增加38到1500,则封装之后,routerA&B的eth1会相应增加到1538.  需要与网络运营商确认siteA和siteB之间的线路连接,如果是云服务器,需要调整云服务器MTU。

 

3. IP fragmentation

  理想情况下,Frame是不可分割时(DF[Don‘t Fragment]为0),Ethernet frames也能通信的。.

  iproute2文档说,tunnel interface有一个选项nopmtudisc (用途是:disable Path MTU Discovery on this tunnel.)

  在此,我们重新创建tunnel interface(同时在routerA&B执行):

routerA# ip link del gretap1
routerA# ip link add gretap1 type gretap local 192.168.200.1 remote 172.16.0.1 dev eth1 nopmtudisc
routerA# ip link set gretap1 mtu 1500
routerA# ip link set gretap1 up
routerA# ip link set gretap1 master br0

  可是如果我们现在从hostA ping (-s 1472)  hostB,却无法ping通,为什么?

  抓包显示,当hostA 发出的包,DF已设置为1,经过GRE时包的DF也为1(即使我们设置了nopmtud),这样就出现了一个不可拆分的包在被静默丢弃。

  所以,我们在HostA发起ping时,如果显式的明确disable DF(可以拆分包),则才可以ping通。

ping -Mdont -s 1472 10.32.0.111
PING 10.32.0.111 (10.32.0.111) 1472(1500) bytes of data.
1480 bytes from 10.32.0.111: icmp_req=1 ttl=64 time=1.26 ms
1480 bytes from 10.32.0.111: icmp_req=2 ttl=64 time=0.932 ms
1480 bytes from 10.32.0.111: icmp_req=3 ttl=64 time=1.01 ms
^C
--- 10.32.0.111 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 0.932/1.071/1.264/0.143 ms

  此时,在routerA&B抓包都显示包被拆分。(拆包通不是最好的体验,但总比不能ping通要好)。因为Linux操作系统默认都是执行PMUTD的,所以这里我们人为地去拆分包,仅能在实验环境求真,不能满足所有应用自由通信的结果。如果需要Linux默认不支持PMUTD,可以设置kernel:

hostA# echo "net.ipv4.ip_no_pmtu_disc = 1 " >> /etc/sysctl.conf
hostA# sysctl -p

# 这里分享gretap encapsulation 图

  首先有一个original ethernet frame最终能达到1514 bytes (1500 IP + 14 ethernet header):

   技术分享图片

  当这个fram被GRE封装后,得到:

  技术分享图片

 

4. NFQUEUE: Clearing DF 

 我们希望尝试标准的工具来解决这个问题,但是是有些难度的:

a. 创建iptables 规则,去match 那些 准备用NFQUEUE处理的  包

b. 然后一个user-space程序,就可以接收、处理这些包,并裁决verdict这些包:[1] 发回iptables(按规则修改这些包) [2]丢弃这些包。 这种通讯原理为  nfnetlink , 这个库主要使用C,但也有使用Perl和Python。  netlink之netfilter Queue详情Click Here.

# 首先,我们需要iptables rule匹配tunneled packet

  我们可以通过 iptables allows tracing 方法,来记录packet 经过了哪些tables和chains。有这些信息,才能方便地制定相应的iptables rule。

  对于outgoing packet ,TRACE结果:

1 TRACE: raw:PREROUTING:policy:2 IN=br0 OUT= PHYSIN=eth0 MAC=00:16:3e:52:ba:6c:00:16:3e:93:08:ca:08:00 SRC=10.32.0.50 DST=10.32.0.111 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=ICMP TYPE=8 CODE=0 ID=819 SEQ=1
2 TRACE: filter:FORWARD:policy:1 IN=br0 OUT=br0 PHYSIN=eth0 PHYSOUT=gretap MAC=00:16:3e:52:ba:6c:00:16:3e:93:08:ca:08:00 SRC=10.32.0.50 DST=10.32.0.111 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=ICMP TYPE=8 CODE=0 ID=819 SEQ=1
3 TRACE: raw:OUTPUT:rule:1 IN= OUT=eth1 SRC=192.168.200.1 DST=172.16.0.1 LEN=122 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=47
4 TRACE: raw:OUTPUT:policy:2 IN= OUT=eth1 SRC=192.168.200.1 DST=172.16.0.1 LEN=122 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=47
5 TRACE: filter:OUTPUT:policy:2 IN= OUT=eth1 SRC=192.168.200.1 DST=172.16.0.1 LEN=122 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=47

  对于reply return packet,TRACE结果:

6 TRACE: raw:PREROUTING:policy:2 IN=eth1 OUT= MAC=00:16:3e:c3:8c:12:00:16:3e:11:b8:8e:08:00 SRC=172.16.0.1 DST=192.168.200.1 LEN=122 TOS=0x00 PREC=0x00 TTL=63 ID=40301 PROTO=47
7 TRACE: filter:INPUT:policy:1 IN=eth1 OUT= MAC=00:16:3e:c3:8c:12:00:16:3e:11:b8:8e:08:00 SRC=172.16.0.1 DST=192.168.200.1 LEN=122 TOS=0x00 PREC=0x00 TTL=63 ID=40301 PROTO=47
8 TRACE: raw:PREROUTING:rule:1 IN=br0 OUT= PHYSIN=gretap MAC=00:16:3e:93:08:ca:00:16:3e:52:ba:6c:08:00 SRC=10.32.0.111 DST=10.32.0.50 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=18065 PROTO=ICMP TYPE=0 CODE=0 ID=819 SEQ=1
9 TRACE: raw:PREROUTING:policy:2 IN=br0 OUT= PHYSIN=gretap MAC=00:16:3e:93:08:ca:00:16:3e:52:ba:6c:08:00 SRC=10.32.0.111 DST=10.32.0.50 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=18065 PROTO=ICMP TYPE=0 CODE=0 ID=819 SEQ=1
10 TRACE: filter:FORWARD:policy:1 IN=br0 OUT=br0 PHYSIN=gretap PHYSOUT=eth0 MAC=00:16:3e:93:08:ca:00:16:3e:52:ba:6c:08:00 SRC=10.32.0.111 DST=10.32.0.50 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=18065 PROTO=ICMP TYPE=0 CODE=0 ID=819 SEQ=1

   请留意:由于涉及bridge,上面的TRACE实际结果需要依靠是否   /proc/sys/net/bridge/bridge-nf-call-iptables 设置为0或1。很多系统默认bridge-nf-call-iptables为1,则会呈现上述TRACE结果;如果为0,则包经过bridge的TRACE记录将不会被显示,也就是上述的步骤1/2/8/9/10步骤不会存在。

  那么,我们得到TRACE记录后,我们究竟tap into哪个flow去获得packets?显然,我们想看到GRE包,我们只关注从local LAN 到tunnel 的traffic(也就是上述TRACE的步骤 3、4、5)。所以,我们这里选择OUTPUT chain,至于raw或filter table,都是OK的。这里,我们选择filter table在routerA&B 操作:

routerA# iptables -A OUTPUT -s 192.168.200.1 -d 172.16.0.1 -p gre -j NFQUEUE --queue-bypass
routerB# iptables -A OUTPUT -s 172.16.0.1 -d 192.168.200.1 -p gre -j NFQUEUE --queue-bypass

   这样就能匹配所有发送traffic 去到NFQUEUE (默认序号queue number为0)。同时,如果程序监听该队列(--queue-bypass,则移动到next policy或rule,所以至少可以通过small packet。

 

# 其次,Clearing DF

  我们需要编写代码去: 

    a. 接收来自 queue number 0 的packet   

    b. 执行clearing DF

    c. 发送处理后的包回到iptables

  幸运的,有一些 案例C代码 可提供我们一些参考。现在,我们可以编写如下代码:

技术分享图片
/***************************************************************************************
 * clear_df.c: clear, uh, DF bit from IPv4 packets. Heavily borrowed from              * 
 * http://netfilter.org/projects/libnetfilter_queue/doxygen/nfqnl__test_8c_source.html *
 ***************************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <linux/types.h>
#include <linux/netfilter.h>            /* for NF_ACCEPT */
#include <arpa/inet.h>
#include <time.h>
#include <libnetfilter_queue/libnetfilter_queue.h>

/* Standard IPv4 header checksum calculation, as per RFC 791 */
u_int16_t ipv4_header_checksum(char *hdr, size_t hdrlen) {

  unsigned long sum = 0;
  const u_int16_t *bbp;
  int count = 0;

  bbp = (u_int16_t *)hdr;
  while (hdrlen > 1) {
    /* the checksum field itself should be considered to be 0 (ie, excluded) when calculating the checksum */
    if (count != 10) {
      sum += *bbp;
    } 
    bbp++; hdrlen -= 2; count += 2;
  }

  /* in case hdrlen was an odd number, there will be one byte left to sum */
  if (hdrlen > 0) {
    sum += *(unsigned char *)bbp;
  }

  while (sum >> 16) {
    sum = (sum & 0xffff) + (sum >> 16);
  }

  return (~sum);
}

/* callback function; this is called for every matched packet. */       
static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) {

  u_int32_t queue_id;
  struct nfqnl_msg_packet_hdr *ph;
  int pkt_len;

  char *buf;
  size_t hdr_len;

  /* determine the id of the packet in the queue */
  ph = nfq_get_msg_packet_hdr(nfa);
  if (ph) {
    queue_id = ntohl(ph->packet_id);
  } else {
    return -1;
  }

  /* try to get at the actual packet */
  pkt_len = nfq_get_payload(nfa, &buf);

  if (pkt_len >= 0) {

    hdr_len = ((buf[0] & 0x0f) * 4);

    /* clear DF bit */
    buf[6] &= 0xbf;

    /* set new packet ID */
    *((u_int16_t *)(buf + 4)) = htons((rand() % 65535) + 1);

    /* recalculate checksum */
    *((u_int16_t *)(buf + 10)) = ipv4_header_checksum(buf, hdr_len);
  }

  /* "accept" the mangled packet */
  return nfq_set_verdict(qh, queue_id, NF_ACCEPT, pkt_len, buf);
}

int main(int argc, char **argv) {

    struct nfq_handle *h;
    struct nfq_q_handle *qh;
    int fd;
    int rv;
    char buf[4096] __attribute__ ((aligned));

    /* printf("opening library handle\n"); */
    h = nfq_open();
    if (!h) {
        fprintf(stderr, "error during nfq_open()\n");
        exit(1);
    }

    /* printf("unbinding existing nf_queue handler for AF_INET (if any)\n"); */
    if (nfq_unbind_pf(h, AF_INET) < 0) {
        fprintf(stderr, "error during nfq_unbind_pf()\n");
        exit(1);
    }

    /* printf("binding nfnetlink_queue as nf_queue handler for AF_INET\n"); */
    if (nfq_bind_pf(h, AF_INET) < 0) {
        fprintf(stderr, "error during nfq_bind_pf()\n");
        exit(1);
    }

    /* printf("binding this socket to queue ‘0‘\n"); */
    qh = nfq_create_queue(h,  0, &cb, NULL);
    if (!qh) {
        fprintf(stderr, "error during nfq_create_queue()\n");
        exit(1);
    }

    /* printf("setting copy_packet mode\n"); */
    if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) {
        fprintf(stderr, "can‘t set packet_copy mode\n");
        exit(1);
    }

    fd = nfq_fd(h);

    /* initialize random number generator */
    srand(time(NULL));

    while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {
        nfq_handle_packet(h, buf, rv);
    }

    /* printf("unbinding from queue 0\n"); */
    nfq_destroy_queue(qh);

    /* printf("closing library handle\n"); */
    nfq_close(h);

    exit(0);
}
View Code

   在说明前,我们可以回顾一下 IPv4 Header Format 图:技术分享图片

 

 

   请留意,如果我们clear DF,则我们需要填充"Indentification" field。当DF设置为1时,Indentification field一般是0,因为这种情况(DF=1)下,包不会被分割,所以不需要Indentification 去标识fragmentation碎片包。而当我们设置DF=0或者说clear DF时,则需要设置Indentification 。此处,我们可以生成一个1-65535的随机数,去填入Indentification field。

  编译需要提供header files:

gcc -o clear_df -lnfnetlink -lnetfilter_queue clear_df.c

# 最后,我们验证clear df效果

routerA# clear_df
routerB# clear_df
hostA# ping -s 1472 -Mdo 10.32.0.111   ##此处我们强制DF,看看效果
PING 10.32.0.111 (10.32.0.111) 1472(1500) bytes of data.
1480 bytes from 10.32.0.111: icmp_req=1 ttl=64 time=1.48 ms
1480 bytes from 10.32.0.111: icmp_req=2 ttl=64 time=0.969 ms
1480 bytes from 10.32.0.111: icmp_req=3 ttl=64 time=1.11 ms
1480 bytes from 10.32.0.111: icmp_req=4 ttl=64 time=0.946 ms
1480 bytes from 10.32.0.111: icmp_req=5 ttl=64 time=0.944 ms
^C
--- 10.32.0.111 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4005ms
rtt min/avg/max/mdev = 0.944/1.091/1.481/0.208 ms

 

5. IPsec

  回到正轨,IPsec是我们的最终目的。为了使实验更精彩,对于IPsec的实现,我们让routerA使用 " ipsec-tools + racoon",routerB使用 openswan 实现。

  此时,在第一个IP header之后,IPsec transport mode将插入一个新的ESP header,以至于Protocol field会由47(GRE)更改为50(ESP),在ESP应用后(当然是,这是是说在未DF前的结构),我们得到如下:

技术分享图片

 

 

   我们再次追踪新结构的packet到user-space,提前做一下TRACE:

1 TRACE: raw:OUTPUT:policy:2 IN= OUT=eth1 SRC=192.168.200.1 DST=172.16.0.1 LEN=122 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=47 
2 TRACE: filter:OUTPUT:rule:2 IN= OUT=eth1 SRC=192.168.200.1 DST=172.16.0.1 LEN=122 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=47 
3 TRACE: raw:OUTPUT:rule:1 IN= OUT=eth1 SRC=192.168.200.1 DST=172.16.0.1 LEN=152 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=ESP SPI=0xdb28966a 
4 TRACE: raw:OUTPUT:policy:2 IN= OUT=eth1 SRC=192.168.200.1 DST=172.16.0.1 LEN=152 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=ESP SPI=0xdb28966a 
5 TRACE: filter:OUTPUT:policy:3 IN= OUT=eth1 SRC=192.168.200.1 DST=172.16.0.1 LEN=152 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=ESP SPI=0xdb28966a 

6 TRACE: raw:PREROUTING:policy:2 IN=eth1 OUT= MAC=00:16:3e:c3:8c:12:00:16:3e:11:b8:8e:08:00 SRC=172.16.0.1 DST=192.168.200.1 LEN=152 TOS=0x00 PREC=0x00 TTL=63 ID=21840 PROTO=ESP SPI=0x4802e17
7 TRACE: filter:INPUT:policy:1 IN=eth1 OUT= MAC=00:16:3e:c3:8c:12:00:16:3e:11:b8:8e:08:00 SRC=172.16.0.1 DST=192.168.200.1 LEN=152 TOS=0x00 PREC=0x00 TTL=63 ID=21840 PROTO=ESP SPI=0x4802e17 
8 TRACE: raw:PREROUTING:rule:1 IN=eth1 OUT= MAC=00:16:3e:c3:8c:12:00:16:3e:11:b8:8e:08:00 SRC=172.16.0.1 DST=192.168.200.1 LEN=122 TOS=0x00 PREC=0x00 TTL=63 ID=21840 PROTO=47 
9 TRACE: raw:PREROUTING:policy:2 IN=eth1 OUT= MAC=00:16:3e:c3:8c:12:00:16:3e:11:b8:8e:08:00 SRC=172.16.0.1 DST=192.168.200.1 LEN=122 TOS=0x00 PREC=0x00 TTL=63 ID=21840 PROTO=47 
10 TRACE: filter:INPUT:policy:1 IN=eth1 OUT= MAC=00:16:3e:c3:8c:12:00:16:3e:11:b8:8e:08:00 SRC=172.16.0.1 DST=192.168.200.1 LEN=122 TOS=0x00 PREC=0x00 TTL=63 ID=21840 PROTO=47 

  Linux 没有真正的 IPsec virtual interface,但我们看到IPsec 穿过2次chain: 

    第1次: before encryption (with PROTO=47, lines 1-2)

    第2次: after encryption (with PROTO=ESP, that is, protocol 50, lines 3-5)

  这意味着我们有2种处理方式:

    第1种:保留现有的iptables rule (但我们的代码将收到未加密的packet)

    第2种:改变匹配协议为ESP  (iptables rule 中使用 -p 50 or -p esp都行)

  在此,我们推荐使用第2种处理方式。因为有一种情况存在:如果使用AH (protocol 51),我们将不能更改ID field。 由于NFQUEUE会在kernel space和 user space之间来回copy packet,且由于没有加密的packet 更小,能够使匹配 Protocol 47更加高效,综合上述原因,我们不对iptables rule做更改。

  这里分享在routerA上的ipsec-tools.conf 配置:

#!/usr/sbin/setkey -f

## Flush the SAD and SPD
#
flush;
spdflush;

spdadd 192.168.200.1/32 172.16.0.1/32 gre -P out ipsec
   esp/transport//require;

spdadd 172.16.0.1/32 192.168.200.1/32 gre -P in ipsec
   esp/transport//require;

racoon.conf on routerA:
log notify;
path pre_shared_key "/etc/racoon/psk.txt";
path certificate "/etc/racoon/certs";

remote 172.16.0.1 {
        exchange_mode main;
        proposal {
                encryption_algorithm 3des;
                hash_algorithm md5;
                authentication_method pre_shared_key;
                dh_group modp1024;
        }
}

sainfo address 192.168.200.1/32 gre address 172.16.0.1/32 gre {
        pfs_group modp1024;
        encryption_algorithm 3des;
        authentication_algorithm hmac_md5;
        compression_algorithm deflate;
}

ipsec.conf on routerB:
version 2.0     # conforms to second version of ipsec.conf specification

# basic configuration
config setup
  nhelpers=0
  interfaces="%none"
  protostack=netkey
  klipsdebug=""
  plutodebug=""

conn to-routerA
  type=transport
  left=172.16.0.1
  leftsubnet=172.16.0.1/32
  right=192.168.200.1
  rightsubnet=192.168.200.1/32
  authby=secret
  phase2alg=3des-md5;modp1024
  keyexchange=ike
  ike=3des-md5;modp1024
  auto=start
  leftprotoport=gre
  rightprotoport=gre

    请留意:上述配置仅加密了GRE流量;身份验证使用了PSK方式。

  

 

 

参考海外英文原稿:Click

 

笔记:Linux上实验 GRE Bridge ,IPsec , NFQUEUE

原文:https://www.cnblogs.com/linetwork/p/12633919.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!