if (!rt) { if (p->flags & XFRM_STATE_ESN) {
NL_SET_ERR_MSG(extack, "Missing required attribute for ESN"); return -EINVAL;
} return 0;
}
rs = nla_data(rt);
if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8) {
NL_SET_ERR_MSG(extack, "ESN bitmap length must be <= 128"); return -EINVAL;
}
if (nla_len(rt) < (int)xfrm_replay_state_esn_len(rs) &&
nla_len(rt) != sizeof(*rs)) {
NL_SET_ERR_MSG(extack, "ESN attribute is too short to fit the full bitmap length"); return -EINVAL;
}
/* As only ESP and AH support ESN feature. */ if ((p->id.proto != IPPROTO_ESP) && (p->id.proto != IPPROTO_AH)) {
NL_SET_ERR_MSG(extack, "ESN only supported for ESP and AH"); return -EINVAL;
}
if (p->replay_window != 0) {
NL_SET_ERR_MSG(extack, "ESN not compatible with legacy replay_window"); return -EINVAL;
}
if (sa_dir == XFRM_SA_DIR_OUT) { if (rs->replay_window) {
NL_SET_ERR_MSG(extack, "Replay window should be 0 for output SA"); return -EINVAL;
} if (rs->seq || rs->seq_hi) {
NL_SET_ERR_MSG(extack, "Replay seq and seq_hi should be 0 for output SA"); return -EINVAL;
}
if (!(p->flags & XFRM_STATE_ESN)) { if (rs->oseq_hi) {
NL_SET_ERR_MSG(
extack, "Replay oseq_hi should be 0 in non-ESN mode for output SA"); return -EINVAL;
} if (rs->oseq == U32_MAX) {
NL_SET_ERR_MSG(
extack, "Replay oseq should be less than 0xFFFFFFFF in non-ESN mode for output SA"); return -EINVAL;
}
} else { if (rs->oseq == U32_MAX && rs->oseq_hi == U32_MAX) {
NL_SET_ERR_MSG(
extack, "Replay oseq and oseq_hi should be less than 0xFFFFFFFF for output SA"); return -EINVAL;
}
} if (rs->bmp_len) {
NL_SET_ERR_MSG(extack, "Replay bmp_len should 0 for output SA"); return -EINVAL;
}
}
if (sa_dir == XFRM_SA_DIR_IN) { if (rs->oseq || rs->oseq_hi) {
NL_SET_ERR_MSG(extack, "Replay oseq and oseq_hi should be 0 for input SA"); return -EINVAL;
} if (!(p->flags & XFRM_STATE_ESN)) { if (rs->seq_hi) {
NL_SET_ERR_MSG(
extack, "Replay seq_hi should be 0 in non-ESN mode for input SA"); return -EINVAL;
}
if (rs->seq == U32_MAX) {
NL_SET_ERR_MSG(
extack, "Replay seq should be less than 0xFFFFFFFF in non-ESN mode for input SA"); return -EINVAL;
}
} else { if (rs->seq == U32_MAX && rs->seq_hi == U32_MAX) {
NL_SET_ERR_MSG(
extack, "Replay seq and seq_hi should be less than 0xFFFFFFFF for input SA"); return -EINVAL;
}
}
}
case IPPROTO_ESP: if (attrs[XFRMA_ALG_COMP]) {
NL_SET_ERR_MSG(extack, "Invalid attribute for ESP: COMP"); goto out;
}
if (!attrs[XFRMA_ALG_AUTH] &&
!attrs[XFRMA_ALG_AUTH_TRUNC] &&
!attrs[XFRMA_ALG_CRYPT] &&
!attrs[XFRMA_ALG_AEAD]) {
NL_SET_ERR_MSG(extack, "Missing required attribute for ESP: at least one of AUTH, AUTH_TRUNC, CRYPT, AEAD"); goto out;
}
if ((attrs[XFRMA_ALG_AUTH] ||
attrs[XFRMA_ALG_AUTH_TRUNC] ||
attrs[XFRMA_ALG_CRYPT]) &&
attrs[XFRMA_ALG_AEAD]) {
NL_SET_ERR_MSG(extack, "Invalid attribute combination for ESP: AEAD can't be used with AUTH, AUTH_TRUNC, CRYPT"); goto out;
}
if (attrs[XFRMA_TFCPAD] &&
p->mode != XFRM_MODE_TUNNEL) {
NL_SET_ERR_MSG(extack, "TFC padding can only be used in tunnel mode"); goto out;
} if ((attrs[XFRMA_IPTFS_DROP_TIME] ||
attrs[XFRMA_IPTFS_REORDER_WINDOW] ||
attrs[XFRMA_IPTFS_DONT_FRAG] ||
attrs[XFRMA_IPTFS_INIT_DELAY] ||
attrs[XFRMA_IPTFS_MAX_QSIZE] ||
attrs[XFRMA_IPTFS_PKT_SIZE]) &&
p->mode != XFRM_MODE_IPTFS) {
NL_SET_ERR_MSG(extack, "IP-TFS options can only be used in IP-TFS mode"); goto out;
} break;
case IPPROTO_COMP: if (!attrs[XFRMA_ALG_COMP]) {
NL_SET_ERR_MSG(extack, "Missing required attribute for COMP: COMP"); goto out;
}
if ((err = verify_aead(attrs, extack))) goto out; if ((err = verify_auth_trunc(attrs, extack))) goto out; if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH, extack))) goto out; if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT, extack))) goto out; if ((err = verify_one_alg(attrs, XFRMA_ALG_COMP, extack))) goto out; if ((err = verify_sec_ctx_len(attrs, extack))) goto out; if ((err = verify_replay(p, attrs, sa_dir, extack))) goto out;
err = -EINVAL; switch (p->mode) { case XFRM_MODE_TRANSPORT: case XFRM_MODE_TUNNEL: case XFRM_MODE_ROUTEOPTIMIZATION: case XFRM_MODE_BEET: break; case XFRM_MODE_IPTFS: if (p->id.proto != IPPROTO_ESP) {
NL_SET_ERR_MSG(extack, "IP-TFS mode only supported with ESP"); goto out;
} if (sa_dir == 0) {
NL_SET_ERR_MSG(extack, "IP-TFS mode requires in or out direction attribute"); goto out;
} break;
if (attrs[XFRMA_MTIMER_THRESH]) { if (!attrs[XFRMA_ENCAP]) {
NL_SET_ERR_MSG(extack, "MTIMER_THRESH attribute can only be set on ENCAP states");
err = -EINVAL; goto out;
}
if (sa_dir == XFRM_SA_DIR_OUT) {
NL_SET_ERR_MSG(extack, "MTIMER_THRESH attribute should not be set on output SA");
err = -EINVAL; goto out;
}
}
if (sa_dir == XFRM_SA_DIR_OUT) { if (p->flags & XFRM_STATE_DECAP_DSCP) {
NL_SET_ERR_MSG(extack, "Flag DECAP_DSCP should not be set for output SA");
err = -EINVAL; goto out;
}
if (p->flags & XFRM_STATE_ICMP) {
NL_SET_ERR_MSG(extack, "Flag ICMP should not be set for output SA");
err = -EINVAL; goto out;
}
if (p->flags & XFRM_STATE_WILDRECV) {
NL_SET_ERR_MSG(extack, "Flag WILDRECV should not be set for output SA");
err = -EINVAL; goto out;
}
if (p->replay_window) {
NL_SET_ERR_MSG(extack, "Replay window should be 0 for output SA");
err = -EINVAL; goto out;
}
if (attrs[XFRMA_IPTFS_DROP_TIME]) {
NL_SET_ERR_MSG(extack, "IP-TFS drop time should not be set for output SA");
err = -EINVAL; goto out;
}
if (attrs[XFRMA_IPTFS_REORDER_WINDOW]) {
NL_SET_ERR_MSG(extack, "IP-TFS reorder window should not be set for output SA");
err = -EINVAL; goto out;
}
if (attrs[XFRMA_REPLAY_VAL]) { struct xfrm_replay_state *replay;
replay = nla_data(attrs[XFRMA_REPLAY_VAL]);
if (replay->seq || replay->bitmap) {
NL_SET_ERR_MSG(extack, "Replay seq and bitmap should be 0 for output SA");
err = -EINVAL; goto out;
}
}
}
if (sa_dir == XFRM_SA_DIR_IN) { if (p->flags & XFRM_STATE_NOPMTUDISC) {
NL_SET_ERR_MSG(extack, "Flag NOPMTUDISC should not be set for input SA");
err = -EINVAL; goto out;
}
if (attrs[XFRMA_SA_EXTRA_FLAGS]) {
u32 xflags = nla_get_u32(attrs[XFRMA_SA_EXTRA_FLAGS]);
if (xflags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP) {
NL_SET_ERR_MSG(extack, "Flag DONT_ENCAP_DSCP should not be set for input SA");
err = -EINVAL; goto out;
}
if (xflags & XFRM_SA_XFLAG_OSEQ_MAY_WRAP) {
NL_SET_ERR_MSG(extack, "Flag OSEQ_MAY_WRAP should not be set for input SA");
err = -EINVAL; goto out;
}
}
if (attrs[XFRMA_IPTFS_DONT_FRAG]) {
NL_SET_ERR_MSG(extack, "IP-TFS don't fragment should not be set for input SA");
err = -EINVAL; goto out;
}
if (attrs[XFRMA_IPTFS_INIT_DELAY]) {
NL_SET_ERR_MSG(extack, "IP-TFS initial delay should not be set for input SA");
err = -EINVAL; goto out;
}
if (attrs[XFRMA_IPTFS_MAX_QSIZE]) {
NL_SET_ERR_MSG(extack, "IP-TFS max queue size should not be set for input SA");
err = -EINVAL; goto out;
}
if (attrs[XFRMA_IPTFS_PKT_SIZE]) {
NL_SET_ERR_MSG(extack, "IP-TFS packet size should not be set for input SA");
err = -EINVAL; goto out;
}
}
if (!sa_dir && attrs[XFRMA_SA_PCPU]) {
NL_SET_ERR_MSG(extack, "SA_PCPU only supported with SA_DIR");
err = -EINVAL; goto out;
}
up = nla_data(rp);
ulen = xfrm_replay_state_esn_len(up);
/* Check the overall length and the internal bitmap length to avoid
* potential overflow. */ if (nla_len(rp) < (int)ulen) {
NL_SET_ERR_MSG(extack, "ESN attribute is too short"); return -EINVAL;
}
if (xfrm_replay_state_esn_len(replay_esn) != ulen) {
NL_SET_ERR_MSG(extack, "New ESN size doesn't match the existing SA's ESN size"); return -EINVAL;
}
if (replay_esn->bmp_len != up->bmp_len) {
NL_SET_ERR_MSG(extack, "New ESN bitmap size doesn't match the existing SA's ESN bitmap"); return -EINVAL;
}
if (up->replay_window > up->bmp_len * sizeof(__u32) * 8) {
NL_SET_ERR_MSG(extack, "ESN replay window is longer than the bitmap"); return -EINVAL;
}
staticstruct xfrm_state *xfrm_state_construct(struct net *net, struct xfrm_usersa_info *p, struct nlattr **attrs, int *errp, struct netlink_ext_ack *extack)
{ struct xfrm_state *x = xfrm_state_alloc(net); int err = -ENOMEM;
if (!x) goto error_no_put;
copy_from_user_state(x, p);
if (attrs[XFRMA_ENCAP]) {
x->encap = kmemdup(nla_data(attrs[XFRMA_ENCAP]), sizeof(*x->encap), GFP_KERNEL); if (x->encap == NULL) goto error;
}
if (attrs[XFRMA_COADDR]) {
x->coaddr = kmemdup(nla_data(attrs[XFRMA_COADDR]), sizeof(*x->coaddr), GFP_KERNEL); if (x->coaddr == NULL) goto error;
}
if (attrs[XFRMA_SA_EXTRA_FLAGS])
x->props.extra_flags = nla_get_u32(attrs[XFRMA_SA_EXTRA_FLAGS]);
if ((err = attach_aead(x, attrs[XFRMA_ALG_AEAD], extack))) goto error; if ((err = attach_auth_trunc(&x->aalg, &x->props.aalgo,
attrs[XFRMA_ALG_AUTH_TRUNC], extack))) goto error; if (!x->props.aalgo) { if ((err = attach_auth(&x->aalg, &x->props.aalgo,
attrs[XFRMA_ALG_AUTH], extack))) goto error;
} if ((err = attach_crypt(x, attrs[XFRMA_ALG_CRYPT], extack))) goto error; if ((err = attach_one_algo(&x->calg, &x->props.calgo,
xfrm_calg_get_byname,
attrs[XFRMA_ALG_COMP], extack))) goto error;
if (attrs[XFRMA_TFCPAD])
x->tfcpad = nla_get_u32(attrs[XFRMA_TFCPAD]);
xfrm_mark_get(attrs, &x->mark);
xfrm_smark_init(attrs, &x->props.smark);
if (attrs[XFRMA_IF_ID])
x->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
if (attrs[XFRMA_SA_DIR])
x->dir = nla_get_u8(attrs[XFRMA_SA_DIR]);
if (attrs[XFRMA_NAT_KEEPALIVE_INTERVAL])
x->nat_keepalive_interval =
nla_get_u32(attrs[XFRMA_NAT_KEEPALIVE_INTERVAL]);
if (attrs[XFRMA_SA_PCPU]) {
x->pcpu_num = nla_get_u32(attrs[XFRMA_SA_PCPU]); if (x->pcpu_num >= num_possible_cpus()) goto error;
}
err = __xfrm_init_state(x, extack); if (err) goto error;
if (attrs[XFRMA_SEC_CTX]) {
err = security_xfrm_state_alloc(x,
nla_data(attrs[XFRMA_SEC_CTX])); if (err) goto error;
}
if ((err = xfrm_alloc_replay_state_esn(&x->replay_esn, &x->preplay_esn,
attrs[XFRMA_REPLAY_ESN_VAL]))) goto error;
x->km.seq = p->seq;
x->replay_maxdiff = net->xfrm.sysctl_aevent_rseqth; /* sysctl_xfrm_aevent_etime is in 100ms units */
x->replay_maxage = (net->xfrm.sysctl_aevent_etime*HZ)/XFRM_AE_ETH_M;
if ((err = xfrm_init_replay(x, extack))) goto error;
/* override default values from above */
xfrm_update_ae_params(x, attrs, 0);
xfrm_set_type_offload(x, attrs[XFRMA_OFFLOAD_DEV]); /* configure the hardware if offload is requested */ if (attrs[XFRMA_OFFLOAD_DEV]) {
err = xfrm_dev_state_add(net, x,
nla_data(attrs[XFRMA_OFFLOAD_DEV]),
extack); if (err) goto error;
}
if (x->mode_cbs && x->mode_cbs->user_init) {
err = x->mode_cbs->user_init(net, x, attrs, extack); if (err) goto error;
}
staticint xfrm_smark_put(struct sk_buff *skb, struct xfrm_mark *m)
{ int ret = 0;
if (m->v | m->m) {
ret = nla_put_u32(skb, XFRMA_SET_MARK, m->v); if (!ret)
ret = nla_put_u32(skb, XFRMA_SET_MARK_MASK, m->m);
} return ret;
}
/* Don't change this without updating xfrm_sa_len! */ staticint copy_to_user_state_extra(struct xfrm_state *x, struct xfrm_usersa_info *p, struct sk_buff *skb)
{ int ret = 0;
copy_to_user_state(x, p);
if (x->props.extra_flags) {
ret = nla_put_u32(skb, XFRMA_SA_EXTRA_FLAGS,
x->props.extra_flags); if (ret) goto out;
}
if (x->coaddr) {
ret = nla_put(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr); if (ret) goto out;
} if (x->lastused) {
ret = nla_put_u64_64bit(skb, XFRMA_LASTUSED, x->lastused,
XFRMA_PAD); if (ret) goto out;
} if (x->aead) {
ret = copy_to_user_aead(x->aead, skb); if (ret) goto out;
} if (x->aalg) {
ret = copy_to_user_auth(x->aalg, skb); if (ret) goto out;
} if (x->ealg) {
ret = copy_to_user_ealg(x->ealg, skb); if (ret) goto out;
} if (x->calg) {
ret = copy_to_user_calg(x->calg, skb); if (ret) goto out;
} if (x->encap) {
ret = copy_to_user_encap(x->encap, skb); if (ret) goto out;
} if (x->tfcpad) {
ret = nla_put_u32(skb, XFRMA_TFCPAD, x->tfcpad); if (ret) goto out;
}
ret = xfrm_mark_put(skb, &x->mark); if (ret) goto out;
ret = xfrm_smark_put(skb, &x->props.smark); if (ret) goto out;
if (x->replay_esn)
ret = nla_put(skb, XFRMA_REPLAY_ESN_VAL,
xfrm_replay_state_esn_len(x->replay_esn),
x->replay_esn); else
ret = nla_put(skb, XFRMA_REPLAY_VAL, sizeof(x->replay),
&x->replay); if (ret) goto out; if(x->xso.dev)
ret = copy_user_offload(&x->xso, skb); if (ret) goto out; if (x->if_id) {
ret = nla_put_u32(skb, XFRMA_IF_ID, x->if_id); if (ret) goto out;
} if (x->security) {
ret = copy_sec_ctx(x->security, skb); if (ret) goto out;
} if (x->mode_cbs && x->mode_cbs->copy_to_user)
ret = x->mode_cbs->copy_to_user(x, skb); if (ret) goto out; if (x->mapping_maxage) {
ret = nla_put_u32(skb, XFRMA_MTIMER_THRESH, x->mapping_maxage); if (ret) goto out;
} if (x->pcpu_num != UINT_MAX) {
ret = nla_put_u32(skb, XFRMA_SA_PCPU, x->pcpu_num); if (ret) goto out;
} if (x->dir)
ret = nla_put_u8(skb, XFRMA_SA_DIR, x->dir);
if (x->nat_keepalive_interval) {
ret = nla_put_u32(skb, XFRMA_NAT_KEEPALIVE_INTERVAL,
x->nat_keepalive_interval); if (ret) goto out;
}
out: return ret;
}
/* A wrapper for nlmsg_multicast() checking that nlsk is still available. * Must be called with RCU read lock.
*/ staticinlineint xfrm_nlmsg_multicast(struct net *net, struct sk_buff *skb,
u32 pid, unsignedint group)
{ struct sock *nlsk = rcu_dereference(net->xfrm.nlsk); struct xfrm_translator *xtr;
if (!nlsk) {
kfree_skb(skb); return -EPIPE;
}
xtr = xfrm_get_translator(); if (xtr) { int err = xtr->alloc_compat(skb, nlmsg_hdr(skb));
xfrm_put_translator(xtr); if (err) {
kfree_skb(skb); return err;
}
}
ret = verify_policy_dir(p->dir, extack); if (ret) return ret; if (p->index && (xfrm_policy_id2dir(p->index) != p->dir)) {
NL_SET_ERR_MSG(extack, "Policy index doesn't match direction"); return -EINVAL;
}
staticvoid copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, int nr)
{ int i;
xp->xfrm_nr = nr; for (i = 0; i < nr; i++, ut++) { struct xfrm_tmpl *t = &xp->xfrm_vec[i];
memcpy(&t->id, &ut->id, sizeof(struct xfrm_id));
memcpy(&t->saddr, &ut->saddr, sizeof(xfrm_address_t));
t->reqid = ut->reqid;
t->mode = ut->mode;
t->share = ut->share;
t->optional = ut->optional;
t->aalgos = ut->aalgos;
t->ealgos = ut->ealgos;
t->calgos = ut->calgos; /* If all masks are ~0, then we allow all algorithms. */
t->allalgs = !~(t->aalgos & t->ealgos & t->calgos);
t->encap_family = ut->family;
}
}
staticint validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family, int dir, struct netlink_ext_ack *extack)
{
u16 prev_family; int i;
if (nr > XFRM_MAX_DEPTH) {
NL_SET_ERR_MSG(extack, "Template count must be <= XFRM_MAX_DEPTH (" __stringify(XFRM_MAX_DEPTH) ")"); return -EINVAL;
}
prev_family = family;
for (i = 0; i < nr; i++) { /* We never validated the ut->family value, so many * applications simply leave it at zero. The check was * never made and ut->family was ignored because all * templates could be assumed to have the same family as * the policy itself. Now that we will have ipv4-in-ipv6 * and ipv6-in-ipv4 tunnels, this is no longer true.
*/ if (!ut[i].family)
ut[i].family = family;
switch (ut[i].mode) { case XFRM_MODE_TUNNEL: case XFRM_MODE_BEET: if (ut[i].optional && dir == XFRM_POLICY_OUT) {
NL_SET_ERR_MSG(extack, "Mode in optional template not allowed in outbound policy"); return -EINVAL;
} break; case XFRM_MODE_IPTFS: break; default: if (ut[i].family != prev_family) {
NL_SET_ERR_MSG(extack, "Mode in template doesn't support a family change"); return -EINVAL;
} break;
} if (ut[i].mode >= XFRM_MODE_MAX) {
NL_SET_ERR_MSG(extack, "Mode in template must be < XFRM_MODE_MAX (" __stringify(XFRM_MODE_MAX) ")"); return -EINVAL;
}
prev_family = ut[i].family;
switch (ut[i].family) { case AF_INET: break; #if IS_ENABLED(CONFIG_IPV6) case AF_INET6: break; #endif default:
NL_SET_ERR_MSG(extack, "Invalid family in template"); return -EINVAL;
}
if (!xfrm_id_proto_valid(ut[i].id.proto)) {
NL_SET_ERR_MSG(extack, "Invalid XFRM protocol in template"); return -EINVAL;
}
}
staticstruct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_userpolicy_info *p, struct nlattr **attrs, int *errp, struct netlink_ext_ack *extack)
{ struct xfrm_policy *xp = xfrm_policy_alloc(net, GFP_KERNEL); int err;
if (!xp) {
*errp = -ENOMEM; return NULL;
}
copy_from_user_policy(xp, p);
err = copy_from_user_policy_type(&xp->type, attrs, extack); if (err) goto error;
if (!(err = copy_from_user_tmpl(xp, attrs, p->dir, extack)))
err = copy_from_user_sec_ctx(xp, attrs); if (err) goto error;
xfrm_mark_get(attrs, &xp->mark);
if (attrs[XFRMA_IF_ID])
xp->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
/* configure the hardware if offload is requested */ if (attrs[XFRMA_OFFLOAD_DEV]) {
err = xfrm_dev_policy_add(net, xp,
nla_data(attrs[XFRMA_OFFLOAD_DEV]),
p->dir, extack); if (err) goto error;
}
err = verify_newpolicy_info(p, extack); if (err) return err;
err = verify_sec_ctx_len(attrs, extack); if (err) return err;
xp = xfrm_policy_construct(net, p, attrs, &err, extack); if (!xp) return err;
/* shouldn't excl be based on nlh flags?? * Aha! this is anti-netlink really i.e more pfkey derived * in netlink excl is a flag and you wouldn't need
* a type XFRM_MSG_UPDPOLICY - JHS */
excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;
err = xfrm_policy_insert(p->dir, xp, excl);
xfrm_audit_policy_add(xp, err ? 0 : 1, true);
if (err) {
xfrm_dev_policy_delete(xp);
xfrm_dev_policy_free(xp);
security_xfrm_policy_free(xp->security);
kfree(xp); return err;
}
staticint xfrm_notify_userpolicy(struct net *net)
{ struct xfrm_userpolicy_default *up; int len = NLMSG_ALIGN(sizeof(*up)); struct nlmsghdr *nlh; struct sk_buff *skb; int err;
skb = nlmsg_new(len, GFP_ATOMIC); if (skb == NULL) return -ENOMEM;
/* * XXX: is this lock really needed - none of the other * gets lock (the concern is things getting updated
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.22Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.