static void
vrrp_update_pkt(vrrp_t *vrrp, uint8_t prio, struct sockaddr_storage *addr)
{
char *bufptr = vrrp->send_buffer;
log_message(LOG_INFO, "%s:%d sent buffer is %s \n", __func__, __LINE__,bufptr);
vrrphdr_t *hd;
#ifdef _WITH_VRRP_AUTH_
bool final_update;
unicast_peer_t *peer = NULL;
#endif
uint32_t new_saddr = 0;
uint32_t new_daddr;
#ifdef _WITH_VRRP_AUTH_
/* We will need to be called again if there is more than one unicast peer, so don't calculate checksums */
if (!list_empty(&vrrp->unicast_peer))
peer = list_first_entry(&vrrp->unicast_peer, unicast_peer_t, e_list);
final_update = (!peer || list_is_last(&peer->e_list, &vrrp->unicast_peer) || addr);
#endif
if (vrrp->family == AF_INET) {
bufptr += sizeof(struct iphdr);
#ifdef _WITH_VRRP_AUTH_
if (vrrp->auth_type == VRRP_AUTH_AH)
bufptr += sizeof(ipsec_ah_t);
#endif
}
hd = PTR_CAST(vrrphdr_t, bufptr);
hd->test_num = htons(1234);
if (hd->priority != prio) {
if (vrrp->family == AF_INET) {
/* HC' = ~(~HC + ~m + m') */
uint16_t *prio_addr = PTR_CAST(uint16_t, ((char *)&hd->priority - (((char *)hd -(char *)&hd->priority) & 1)));
uint16_t old_val = *prio_addr;
hd->priority = prio;
hd->chksum = csum_incremental_update16(hd->chksum, old_val, *prio_addr);
}
else
hd->priority = prio;
}
if (vrrp->family == AF_INET) {
struct iphdr *ip = PTR_CAST(struct iphdr, (vrrp->send_buffer));
if (!addr) {
/* kernel will fill in ID if left to 0, so we overflow to 1 */
if (!++vrrp->ip_id)
++vrrp->ip_id;
ip->id = htons(vrrp->ip_id);
}
else {
/* If unicast address */
if (vrrp->version == VRRP_VERSION_2)
ip->daddr = inet_sockaddrip4(addr);
else {
new_daddr = inet_sockaddrip4(addr);
if (ip->daddr != new_daddr) {
#ifdef _WITH_UNICAST_CHKSUM_COMPAT_
if (vrrp->unicast_chksum_compat < CHKSUM_COMPATIBILITY_MIN_COMPAT)
#endif
hd->chksum = csum_incremental_update32(hd->chksum, ip->daddr, new_daddr);
ip->daddr = new_daddr;
}
}
}
/* Has the source address changed? */
if (!vrrp->saddr_from_config &&
ip->saddr != PTR_CAST(struct sockaddr_in, &vrrp->saddr)->sin_addr.s_addr) {
if (vrrp->version == VRRP_VERSION_2)
ip->saddr = PTR_CAST(struct sockaddr_in, &vrrp->saddr)->sin_addr.s_addr;
else {
new_saddr = PTR_CAST(struct sockaddr_in, &vrrp->saddr)->sin_addr.s_addr;
hd->chksum = csum_incremental_update32(hd->chksum, ip->saddr, new_saddr);
ip->saddr = new_saddr;
}
}
//jhw
if (vrrp->version == VRRP_VERSION_2) {
size_t len = sizeof(vrrphdr_t) + hd->naddr * sizeof(struct in_addr) + VRRP_AUTH_LEN;
uint16_t new_csum = in_csum(PTR_CAST(uint16_t, hd), len, 0, NULL);
hd->chksum = new_csum;
} else if (vrrp->version == VRRP_VERSION_3) {
size_t len = sizeof(vrrphdr_t) + hd->naddr * sizeof(struct in_addr);
uint16_t new_csum = in_csum(PTR_CAST(uint16_t, hd), len, 0, NULL);
hd->chksum = new_csum;
}
#ifdef _WITH_VRRP_AUTH_
if (vrrp->auth_type == VRRP_AUTH_AH) {
unsigned char digest[MD5_DIGEST_LENGTH];
ipsec_ah_t *ah = PTR_CAST(ipsec_ah_t, (vrrp->send_buffer + sizeof (struct iphdr)));
if (new_saddr)
ah->spi = new_saddr;
if (!addr) {
/* Processing sequence number.
Cycled assumed if 0xFFFFFFFD reached. So the MASTER state is free for another srv.
Here can result a flapping MASTER state owner when max seq_number value reached.
=> We REALLY REALLY REALLY don't need to worry about this. We only use authentication
for VRRPv2, for which the adver_int is specified in whole seconds, therefore the minimum
adver_int is 1 second. 2^32-3 seconds is 4294967293 seconds, or in excess of 136 years,
so since the sequence number always starts from 0, we are not going to reach the limit.
In the current implementation if counter has cycled, we stop sending adverts and
become BACKUP. We are ever the optimist and think we might run continuously for over
136 years without someone redesigning their network!
If all the master are down we reset the counter for becoming MASTER.
*/
if (vrrp->ipsecah_counter.seq_number > 0xFFFFFFFD) {
vrrp->ipsecah_counter.cycle = true;
} else {
vrrp->ipsecah_counter.seq_number++;
}
ah->seq_number = htonl(vrrp->ipsecah_counter.seq_number);
}
if (final_update) {
struct iphdr iph = *ip;
/* zero the ip mutable fields */
iph.tos = 0;
iph.frag_off = 0;
if (!list_empty(&vrrp->unicast_peer))
iph.ttl = 0;
/* Compute the ICV & trunc the digest to 96bits
=> No padding needed.
-- rfc2402.3.3.3.1.1.1 & rfc2401.5
*/
memset(&ah->auth_data, 0, sizeof(ah->auth_data));
hmac_md5(PTR_CAST_CONST(unsigned char, &iph), sizeof iph, PTR_CAST_CONST(unsigned char, ah),
vrrp->send_buffer_size - sizeof(struct iphdr), vrrp->auth_data,
sizeof(vrrp->auth_data), digest);
memcpy(ah->auth_data, digest, HMAC_MD5_TRUNC);
}
}
#endif
}
log_message(LOG_INFO, "%s:%d sent buffer is %s \n", __func__, __LINE__,bufptr);
}这个函数做了哪些工作,通俗地解释下,把关键的信息详细说明下