Ejemplo n.º 1
0
DEBUG_NO_STATIC int
pfkey_x_ext_saref_parse(struct sadb_ext *pfkey_ext)
{
	int error = 0;
	struct sadb_x_saref *p = (struct sadb_x_saref *)pfkey_ext;
	
	DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_x_saref_parse:\n");
	/* sanity checks... */
	
	if (p->sadb_x_saref_len != IPSEC_PFKEYv2_WORDS(sizeof(*p))) {
		    DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
			      "pfkey_x_saref_parse: size wrong ext_len=%d, key_ext_len=%d.\n",
			      p->sadb_x_saref_len, (int)sizeof(*p));
		    SENDERR(EINVAL);
	}
	
 errlab:
	return error;
}
Ejemplo n.º 2
0
void
pfkey_print(struct sadb_msg *msg, FILE *out)
{
    int len;
    struct sadb_ext *se;
    
    fprintf(out, "version=%d type=%d errno=%d satype=%d len=%d seq=%d pid=%d ",
	    msg->sadb_msg_version,
	    msg->sadb_msg_type,
	    msg->sadb_msg_errno,
	    msg->sadb_msg_satype,
	    msg->sadb_msg_len,
	    (int)msg->sadb_msg_seq,
	    (int)msg->sadb_msg_pid);
    
    len = IPSEC_PFKEYv2_LEN(msg->sadb_msg_len);
    len -= sizeof(struct sadb_msg);
    
    se = (struct sadb_ext *)(&msg[1]);
    while(len > sizeof(struct sadb_ext)) {
	fprintf(out, "{ext=%d len=%d ", se->sadb_ext_type, se->sadb_ext_len);
	
	/* make sure that there is enough left */
	if(IPSEC_PFKEYv2_LEN(se->sadb_ext_len) > len) {
	    fprintf(out, "short-packet(%d<%d) ", len,
		    (int)IPSEC_PFKEYv2_LEN(se->sadb_ext_len));
	    
	    /* force it to match */
	    se->sadb_ext_len = IPSEC_PFKEYv2_WORDS(len);
	    goto dumpbytes;
	}
	
	/* okay, decode what we know */
	switch(se->sadb_ext_type) {
	case SADB_EXT_SA:
	  {
	    struct k_sadb_sa *sa = (struct k_sadb_sa *)se;
	    fprintf(out, "spi=%08x replay=%d state=%d auth=%d encrypt=%d flags=%08x ref=%08x}",
		    (int)sa->sadb_sa_spi,
		    sa->sadb_sa_replay,
		    sa->sadb_sa_state,
		    sa->sadb_sa_auth,
		    sa->sadb_sa_encrypt,
		    (int)sa->sadb_sa_flags,
		    (int)sa->sadb_x_sa_ref);
	  }
	  break;
	  
	case SADB_X_EXT_ADDRESS_SRC_FLOW: 
	case SADB_X_EXT_ADDRESS_DST_FLOW: 
	case SADB_X_EXT_ADDRESS_SRC_MASK: 
	case SADB_X_EXT_ADDRESS_DST_MASK:
	case SADB_EXT_ADDRESS_DST:        
	case SADB_EXT_ADDRESS_SRC:        
	  {
	    struct sadb_address *addr = (struct sadb_address *)se;
	    int    alen = IPSEC_PFKEYv2_LEN(addr->sadb_address_len)-sizeof(struct sadb_address);
	    unsigned char *bytes = (unsigned char *)&addr[1];

	    fprintf(out, "proto=%d prefixlen=%d addr=0x",
		    addr->sadb_address_proto,
		    addr->sadb_address_prefixlen);

	    while(alen > 0)
	      {
		fprintf(out, "%02x", *bytes);
		bytes++;
		alen--;
	      }
	    fprintf(out, " } ");
	  }
	  break;
	  
	case SADB_X_EXT_PROTOCOL:
	  {
	    struct sadb_protocol *sp = (struct sadb_protocol *)se;
	    fprintf(out, "proto=%d direction=%d flags=%d } ",
		    sp->sadb_protocol_proto,
		    sp->sadb_protocol_direction,
		    sp->sadb_protocol_flags);
	  }
	  break;

	case SADB_EXT_LIFETIME_CURRENT:   
	case SADB_EXT_LIFETIME_HARD:      
	case SADB_EXT_LIFETIME_SOFT:      
	  {
	    struct sadb_lifetime *life = (struct sadb_lifetime *)se;

	    fprintf(out, "allocations=%d bytes=%qd addtime=%qd usetime=%qd packets=%d",
		    (int)life->sadb_lifetime_allocations,
		    (long long)life->sadb_lifetime_bytes,
		    (long long)life->sadb_lifetime_addtime,
		    (long long)life->sadb_lifetime_usetime,
		    (int)life->sadb_x_lifetime_packets);
	    fprintf(out, " } ");
	  }
	  break;
	  
	  
	case SADB_EXT_RESERVED:
	case SADB_EXT_ADDRESS_PROXY:      
	case SADB_EXT_KEY_AUTH:           
	case SADB_EXT_KEY_ENCRYPT:        
	case SADB_EXT_IDENTITY_SRC:       
	case SADB_EXT_IDENTITY_DST:       
	case SADB_EXT_SENSITIVITY:        
	case SADB_EXT_PROPOSAL:           
	case SADB_EXT_SUPPORTED_AUTH:     
	case SADB_EXT_SUPPORTED_ENCRYPT:  
	case SADB_EXT_SPIRANGE:           
	case SADB_X_EXT_KMPRIVATE:
	case SADB_X_EXT_SATYPE2:
	case SADB_X_EXT_SA2:
	case SADB_X_EXT_ADDRESS_DST2:     
	case SADB_X_EXT_DEBUG:
	default:
	  {
	    unsigned int elen;
	    unsigned char *bytes;
	    
	  dumpbytes:
	    
	    elen = IPSEC_PFKEYv2_LEN(se->sadb_ext_len)-sizeof(struct sadb_ext);
	    bytes = (unsigned char *)&se[1];
	    
	    fprintf(out, "bytes=0x");
	    while(elen > 0)
	      {
		fprintf(out, "%02x", *bytes);
		bytes++;
		elen--;
	      }
	    fprintf(out, " } ");
	  }
	  break;
	}

	/* skip to next extension header */
	{
	  unsigned int elen = IPSEC_PFKEYv2_LEN(se->sadb_ext_len);

	  if(elen < sizeof(struct sadb_ext)) {
	    fprintf(out, "illegal-length(%d) ",elen);
	    elen = sizeof(struct sadb_ext);
	  }

	  se = (struct sadb_ext *)(((unsigned char *)se)+elen);
	  len -= elen;
	}
    }
    fprintf(out, "\n");
}
Ejemplo n.º 3
0
int
pfkey_msg_parse(struct sadb_msg *pfkey_msg,
		struct pf_key_ext_parsers_def *ext_parsers[],
		struct sadb_ext *extensions[],
		int dir)
{
	int error = 0;
	int remain;
	struct sadb_ext *pfkey_ext;
	pfkey_ext_track extensions_seen = 0;
	
	DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
		  "pfkey_msg_parse: "
		  "parsing message ver=%d, type=%d(%s), errno=%d, satype=%d(%s), len=%d, res=%d, seq=%d, pid=%d.\n", 
		  pfkey_msg->sadb_msg_version,
		  pfkey_msg->sadb_msg_type,
		  pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type),
		  pfkey_msg->sadb_msg_errno,
		  pfkey_msg->sadb_msg_satype,
		  satype2name(pfkey_msg->sadb_msg_satype),
		  pfkey_msg->sadb_msg_len,
		  pfkey_msg->sadb_msg_reserved,
		  pfkey_msg->sadb_msg_seq,
		  pfkey_msg->sadb_msg_pid);
	
	if(ext_parsers == NULL) ext_parsers = ext_default_parsers;
	
	pfkey_extensions_init(extensions);
	
	remain = pfkey_msg->sadb_msg_len;
	remain -= IPSEC_PFKEYv2_WORDS(sizeof(struct sadb_msg));
	
	pfkey_ext = (struct sadb_ext*)((char*)pfkey_msg +
				       sizeof(struct sadb_msg));
	
	extensions[0] = (struct sadb_ext *) pfkey_msg;
	
	
	if(pfkey_msg->sadb_msg_version != PF_KEY_V2) {
		ERROR("pfkey_msg_parse: "
			"not PF_KEY_V2 msg, found %d, should be %d.\n",
			pfkey_msg->sadb_msg_version,
			PF_KEY_V2);
		SENDERR(EINVAL);
	}

	if(!pfkey_msg->sadb_msg_type) {
		ERROR("pfkey_msg_parse: "
			"msg type not set, must be non-zero..\n");
		SENDERR(EINVAL);
	}

	if(pfkey_msg->sadb_msg_type > K_SADB_MAX) {
		ERROR("pfkey_msg_parse: "
			"msg type=%d > max=%d.\n",
			pfkey_msg->sadb_msg_type,
			K_SADB_MAX);
		SENDERR(EINVAL);
	}

	switch(pfkey_msg->sadb_msg_type) {
	case K_SADB_GETSPI:
	case K_SADB_UPDATE:
	case K_SADB_ADD:
	case K_SADB_DELETE:
	case K_SADB_GET:
	case K_SADB_X_GRPSA:
	case K_SADB_X_ADDFLOW:
		if(!satype2proto(pfkey_msg->sadb_msg_satype)) {
			ERROR("pfkey_msg_parse: "
				  "satype %d conversion to proto failed for msg_type %d (%s).\n",
				  pfkey_msg->sadb_msg_satype,
				  pfkey_msg->sadb_msg_type,
				  pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type));
			SENDERR(EINVAL);
		} else {
			DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
				  "pfkey_msg_parse: "
				  "satype %d(%s) conversion to proto gives %d for msg_type %d(%s).\n",
				  pfkey_msg->sadb_msg_satype,
				  satype2name(pfkey_msg->sadb_msg_satype),
				  satype2proto(pfkey_msg->sadb_msg_satype),
				  pfkey_msg->sadb_msg_type,
				  pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type));
		}
	case K_SADB_ACQUIRE:
	case K_SADB_REGISTER:
	case K_SADB_EXPIRE:
		if(!pfkey_msg->sadb_msg_satype) {
			DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
				  "pfkey_msg_parse: "
				  "satype is zero, must be non-zero for msg_type %d(%s).\n",
				  pfkey_msg->sadb_msg_type,
				  pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type));
			SENDERR(EINVAL);
		}
	default:
		break;
	}
	
	/* errno must not be set in downward messages */
	/* this is not entirely true... a response to an ACQUIRE could return an error */
	if((dir == EXT_BITS_IN) && (pfkey_msg->sadb_msg_type != K_SADB_ACQUIRE) && pfkey_msg->sadb_msg_errno) {
		DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
			    "pfkey_msg_parse: "
			    "errno set to %d.\n",
			    pfkey_msg->sadb_msg_errno);
		SENDERR(EINVAL);
	}

	DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
		  "pfkey_msg_parse: "
		  "remain=%d\n", 
		  remain
		  );

	extensions_seen = 1;
	
	while( (remain * IPSEC_PFKEYv2_ALIGN) >= sizeof(struct sadb_ext) ) {
		/* Is there enough message left to support another extension header? */
		if(remain < pfkey_ext->sadb_ext_len) {
			ERROR("pfkey_msg_parse: "
				"remain %d less than ext len %d.\n", 
				remain, pfkey_ext->sadb_ext_len);
			SENDERR(EINVAL);
		}
		
		DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
			"pfkey_msg_parse: "
			"parsing ext type=%d(%s) remain=%d.\n",
			pfkey_ext->sadb_ext_type,
			pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
			remain);
		
		/* Is the extension header type valid? */
		if((pfkey_ext->sadb_ext_type > K_SADB_EXT_MAX) || (!pfkey_ext->sadb_ext_type)) {
			DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
				"pfkey_msg_parse: "
				"ext type %d(%s) invalid, K_SADB_EXT_MAX=%d.\n", 
				pfkey_ext->sadb_ext_type,
				pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
				K_SADB_EXT_MAX);
			SENDERR(EINVAL);
		}
		
		/* Have we already seen this type of extension? */
		if(extensions[pfkey_ext->sadb_ext_type] != NULL)
		{
			ERROR("pfkey_msg_parse: "
				"ext type %d(%s) already seen.\n", 
				pfkey_ext->sadb_ext_type,
				pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
			SENDERR(EINVAL);
		}

		/* Do I even know about this type of extension? */
		if(ext_parsers[pfkey_ext->sadb_ext_type]==NULL) {
			ERROR("pfkey_msg_parse: "
				"ext type %d(%s) unknown, ignoring.\n", 
				pfkey_ext->sadb_ext_type,
				pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
			goto next_ext;
		}

		/* Is this type of extension permitted for this type of message? */
		if(!pfkey_permitted_extension(dir,pfkey_msg->sadb_msg_type,pfkey_ext->sadb_ext_type)) {
			ERROR("ext type %d(%s) not permitted (parse)\n", 
			      pfkey_ext->sadb_ext_type, 
			      pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
			SENDERR(EINVAL);
		}

		DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
			  "pfkey_msg_parse: "
			  "remain=%d ext_type=%d(%s) ext_len=%d parsing ext 0p%p with parser %s.\n",
			  remain,
			  pfkey_ext->sadb_ext_type,
			  pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
			  pfkey_ext->sadb_ext_len,
			  pfkey_ext,
			  ext_parsers[pfkey_ext->sadb_ext_type]->parser_name);
		
		/* Parse the extension */
		if((error =
		    (*ext_parsers[pfkey_ext->sadb_ext_type]->parser)(pfkey_ext))) {
			ERROR("pfkey_msg_parse: "
				"extension parsing for type %d(%s) failed with error %d.\n",
				pfkey_ext->sadb_ext_type,
				pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
				error); 
			SENDERR(-error);
		}
		DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
			"pfkey_msg_parse: "
			"Extension %d(%s) parsed.\n",
			pfkey_ext->sadb_ext_type,
			pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
		
		/* Mark that we have seen this extension and remember the header location */
		extensions[pfkey_ext->sadb_ext_type] = pfkey_ext;
		pfkey_mark_extension(pfkey_ext->sadb_ext_type,&extensions_seen);

	next_ext:		
		/* Calculate how much message remains */
		remain -= pfkey_ext->sadb_ext_len;

		if(!remain) {
			break;
		}
		/* Find the next extension header */
		pfkey_ext = (struct sadb_ext*)((char*)pfkey_ext +
			pfkey_ext->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
	}

	if(remain) {
		DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
			"pfkey_msg_parse: "
			"unexpected remainder of %d.\n", 
			remain);
		/* why is there still something remaining? */
		SENDERR(EINVAL);
	}

	/* don't check further if it is an error return message since it
	   may not have a body */
	if(pfkey_msg->sadb_msg_errno) {
		SENDERR(-error);
	}

	if(pfkey_extensions_missing(dir,pfkey_msg->sadb_msg_type,extensions_seen)) {
		ERROR("required extensions missing.seen=%08llx.\n",(unsigned long long)extensions_seen);
		SENDERR(EINVAL);
	}
	
	if((dir == EXT_BITS_IN) && (pfkey_msg->sadb_msg_type == K_SADB_X_DELFLOW)
	   && ((extensions_seen	& K_SADB_X_EXT_ADDRESS_DELFLOW)
	       != K_SADB_X_EXT_ADDRESS_DELFLOW)
	   && (((extensions_seen & (1<<SADB_EXT_SA)) != (1<<SADB_EXT_SA))
	   || ((((struct k_sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_flags
		& SADB_X_SAFLAGS_CLEARFLOW)
	       != SADB_X_SAFLAGS_CLEARFLOW))) {
		DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
			"pfkey_msg_parse: "
			"required SADB_X_DELFLOW extensions missing: either %16llx must be present or %16llx must be present with SADB_X_SAFLAGS_CLEARFLOW set.\n",
			(unsigned long long)K_SADB_X_EXT_ADDRESS_DELFLOW
			- (extensions_seen & K_SADB_X_EXT_ADDRESS_DELFLOW),
			(unsigned long long)(1<<SADB_EXT_SA) - (extensions_seen & (1<<SADB_EXT_SA)));
		SENDERR(EINVAL);
	}
	
	switch(pfkey_msg->sadb_msg_type) {
	case K_SADB_ADD:
	case K_SADB_UPDATE:
		/* check maturity */
		if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state !=
		   K_SADB_SASTATE_MATURE) {
			DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
				"pfkey_msg_parse: "
				"state=%d for add or update should be MATURE=%d.\n",
				((struct k_sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state,
				K_SADB_SASTATE_MATURE);
			SENDERR(EINVAL);
		}
		
		/* check AH and ESP */
		switch(((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype) {
		case SADB_SATYPE_AH:
			if(!(((struct k_sadb_sa*)extensions[SADB_EXT_SA]) &&
			     ((struct k_sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_auth !=
			     SADB_AALG_NONE)) {
				ERROR("pfkey_msg_parse: "
					"auth alg is zero, must be non-zero for AH SAs.\n");
				SENDERR(EINVAL);
			}
			if(((struct k_sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt !=
			   SADB_EALG_NONE) {
				ERROR("pfkey_msg_parse: "
					"AH handed encalg=%d, must be zero.\n",
					((struct k_sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt);
				SENDERR(EINVAL);
			}
			break;
		case SADB_SATYPE_ESP:
			if(!(((struct k_sadb_sa*)extensions[SADB_EXT_SA]) &&
			     ((struct k_sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt !=
			     SADB_EALG_NONE)) {
				ERROR("pfkey_msg_parse: "
					"encrypt alg=%d is zero, must be non-zero for ESP=%d SAs.\n",
					((struct k_sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt,
					((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype);
				SENDERR(EINVAL);
			}
			if((((struct k_sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt ==
			    SADB_EALG_NULL) &&
			   (((struct k_sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth ==
			    SADB_AALG_NONE) ) {
				ERROR("pfkey_msg_parse: "
					"ESP handed encNULL+authNONE, illegal combination.\n");
				SENDERR(EINVAL);
			}
			break;
		case K_SADB_X_SATYPE_COMP:
			if(!(((struct k_sadb_sa*)extensions[SADB_EXT_SA]) &&
			     ((struct k_sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt !=
			     SADB_EALG_NONE)) {
				ERROR("pfkey_msg_parse: "
					"encrypt alg=%d is zero, must be non-zero for COMP=%d SAs.\n",
					((struct k_sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt,
					((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype);
				SENDERR(EINVAL);
			}
			if(((struct k_sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth !=
			   SADB_AALG_NONE) {
			        ERROR("pfkey_msg_parse: "
					"COMP handed auth=%d, must be zero.\n",
					((struct k_sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth);
				SENDERR(EINVAL);
			}
			break;
		default:
			break;
		}
		if(ntohl(((struct k_sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi) <= 255) {
			DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
				"pfkey_msg_parse: "
				"spi=%08x must be > 255.\n",
				ntohl(((struct k_sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi));
			SENDERR(EINVAL);
		}
	default:	
		break;
	}

errlab:
	return error;
}